diff options
Diffstat (limited to 'src')
7 files changed, 219 insertions, 44 deletions
diff --git a/src/com/android/messaging/ui/UIIntents.java b/src/com/android/messaging/ui/UIIntents.java index 495732f..10fb391 100644 --- a/src/com/android/messaging/ui/UIIntents.java +++ b/src/com/android/messaging/ui/UIIntents.java @@ -47,6 +47,9 @@ public abstract class UIIntents { // The request code for picking a media from the Document picker. public static final int REQUEST_PICK_MEDIA_FROM_DOCUMENT_PICKER = 1400; + // The request code for picking a contact card from existing Contacts apps. + public static final int REQUEST_PICK_CONTACT_CARD = 1500; + // Indicates what type of notification this applies to (See BugleNotifications: // UPDATE_NONE, UPDATE_MESSAGES, UPDATE_ERRORS, UPDATE_ALL) public static final String UI_INTENT_EXTRA_NOTIFICATIONS_UPDATE = "notifications_update"; @@ -169,13 +172,20 @@ public abstract class UIIntents { public abstract void launchAddContactActivity(final Context context, final String destination); /** - * Launch an activity to show the document picker to pick an image/video. + * Launch an activity to show the document picker to pick an image/video/audio. * * @param fragment the requesting fragment */ public abstract void launchDocumentImagePicker(final Fragment fragment); /** + * Launch an activity to show the contacts list to pick one. + * + * @param fragment the requesting fragment + */ + public abstract void launchContactCardPicker(final Fragment fragment); + + /** * Launch an activity to show people & options for a given conversation. */ public abstract void launchPeopleAndOptionsActivity(final Activity context, diff --git a/src/com/android/messaging/ui/UIIntentsImpl.java b/src/com/android/messaging/ui/UIIntentsImpl.java index cc20065..9281899 100644 --- a/src/com/android/messaging/ui/UIIntentsImpl.java +++ b/src/com/android/messaging/ui/UIIntentsImpl.java @@ -243,6 +243,19 @@ public class UIIntentsImpl extends UIIntents { } @Override + public void launchContactCardPicker(final Fragment fragment) { + final Intent intent = new Intent(Intent.ACTION_PICK); + intent.setType(Contacts.CONTENT_TYPE); + + try { + fragment.startActivityForResult(intent, REQUEST_PICK_CONTACT_CARD); + } catch (final ActivityNotFoundException ex) { + LogUtil.w(LogUtil.BUGLE_TAG, "Couldn't find activity:", ex); + UiUtils.showToastAtBottom(R.string.activity_not_found_message); + } + } + + @Override public void launchPeopleAndOptionsActivity(final Activity activity, final String conversationId) { final Intent intent = new Intent(activity, PeopleAndOptionsActivity.class); diff --git a/src/com/android/messaging/ui/mediapicker/ContactMediaChooser.java b/src/com/android/messaging/ui/mediapicker/ContactMediaChooser.java new file mode 100644 index 0000000..a81ed08 --- /dev/null +++ b/src/com/android/messaging/ui/mediapicker/ContactMediaChooser.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.messaging.ui.mediapicker; + +import android.Manifest; +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; +import android.provider.ContactsContract.Contacts; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.android.messaging.R; +import com.android.messaging.datamodel.data.PendingAttachmentData; +import com.android.messaging.ui.UIIntents; +import com.android.messaging.util.ContactUtil; +import com.android.messaging.util.ContentType; +import com.android.messaging.util.SafeAsyncTask; + +/** + * Chooser which allows the user to select an existing contact from contacts apps on this device. + * Note that this chooser requires the Manifest.permission.READ_CONTACTS which is one of the miminum + * set of permissions for this app. Thus no case to request READ_CONTACTS permission on it actually. + */ +class ContactMediaChooser extends MediaChooser { + private View mEnabledView; + private View mMissingPermissionView; + + ContactMediaChooser(final MediaPicker mediaPicker) { + super(mediaPicker); + } + + @Override + public int getSupportedMediaTypes() { + return MediaPicker.MEDIA_TYPE_VCARD; + } + + @Override + public int getIconResource() { + return R.drawable.ic_person_light; + } + + @Override + public int getIconDescriptionResource() { + return R.string.mediapicker_contactChooserDescription; + } + + @Override + int getActionBarTitleResId() { + return R.string.mediapicker_contact_title; + } + + @Override + protected View createView(final ViewGroup container) { + final LayoutInflater inflater = getLayoutInflater(); + final View view = + inflater.inflate( + R.layout.mediapicker_contact_chooser, + container /* root */, + false /* attachToRoot */); + mEnabledView = view.findViewById(R.id.mediapicker_enabled); + mMissingPermissionView = view.findViewById(R.id.missing_permission_view); + mEnabledView.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(final View v) { + // Launch an external picker to pick a contact as attachment. + UIIntents.get().launchContactCardPicker(mMediaPicker); + } + }); + return view; + } + + @Override + protected void setSelected(final boolean selected) { + super.setSelected(selected); + if (selected && !ContactUtil.hasReadContactsPermission()) { + mMediaPicker.requestPermissions( + new String[] {Manifest.permission.READ_CONTACTS}, + MediaPicker.READ_CONTACT_PERMISSION_REQUEST_CODE); + } + } + + @Override + protected void onRequestPermissionsResult( + final int requestCode, final String permissions[], final int[] grantResults) { + if (requestCode == MediaPicker.READ_CONTACT_PERMISSION_REQUEST_CODE) { + final boolean permissionGranted = grantResults[0] == PackageManager.PERMISSION_GRANTED; + mEnabledView.setVisibility(permissionGranted ? View.VISIBLE : View.GONE); + mMissingPermissionView.setVisibility(permissionGranted ? View.GONE : View.VISIBLE); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == UIIntents.REQUEST_PICK_CONTACT_CARD + && resultCode == Activity.RESULT_OK) { + Uri contactUri = data.getData(); + if (contactUri != null) { + String lookupKey = null; + try (final Cursor c = getContext().getContentResolver().query( + contactUri, + new String[] {Contacts.LOOKUP_KEY}, + null, + null, + null)) { + if (c != null) { + c.moveToFirst(); + lookupKey = c.getString(0); + } + } + final Uri vCardUri = Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, lookupKey); + if (vCardUri != null) { + SafeAsyncTask.executeOnThreadPool(new Runnable() { + @Override + public void run() { + final PendingAttachmentData pendingItem = + PendingAttachmentData.createPendingAttachmentData( + ContentType.TEXT_VCARD.toLowerCase(), vCardUri); + mMediaPicker.dispatchPendingItemAdded(pendingItem); + } + }); + } + } + } + } +} diff --git a/src/com/android/messaging/ui/mediapicker/DocumentImagePicker.java b/src/com/android/messaging/ui/mediapicker/DocumentImagePicker.java index d6de128..c36467c 100644 --- a/src/com/android/messaging/ui/mediapicker/DocumentImagePicker.java +++ b/src/com/android/messaging/ui/mediapicker/DocumentImagePicker.java @@ -15,7 +15,6 @@ */ package com.android.messaging.ui.mediapicker; -import android.app.Activity; import android.app.Fragment; import android.content.Intent; import android.net.Uri; @@ -79,30 +78,27 @@ public class DocumentImagePicker { * Must be called from the fragment/activity's onActivityResult(). */ public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { - if (requestCode == UIIntents.REQUEST_PICK_MEDIA_FROM_DOCUMENT_PICKER - && resultCode == Activity.RESULT_OK) { - // Sometimes called after media item has been picked from the document picker. - String url = data.getStringExtra(EXTRA_PHOTO_URL); + // Sometimes called after media item has been picked from the document picker. + String url = data.getStringExtra(EXTRA_PHOTO_URL); + if (url == null) { + // we're using the builtin photo picker which supplies the return + // url as it's "data" + url = data.getDataString(); if (url == null) { - // we're using the builtin photo picker which supplies the return - // url as it's "data" - url = data.getDataString(); - if (url == null) { - final Bundle extras = data.getExtras(); - if (extras != null) { - final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM); - if (uri != null) { - url = uri.toString(); - } + final Bundle extras = data.getExtras(); + if (extras != null) { + final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM); + if (uri != null) { + url = uri.toString(); } } } + } - // Guard against null uri cases for when the activity returns a null/invalid intent. - if (url != null) { - final Uri uri = Uri.parse(url); - prepareDocumentForAttachment(uri); - } + // Guard against null uri cases for when the activity returns a null/invalid intent. + if (url != null) { + final Uri uri = Uri.parse(url); + prepareDocumentForAttachment(uri); } } diff --git a/src/com/android/messaging/ui/mediapicker/GalleryMediaChooser.java b/src/com/android/messaging/ui/mediapicker/GalleryMediaChooser.java index c9b544d..6192c4f 100644 --- a/src/com/android/messaging/ui/mediapicker/GalleryMediaChooser.java +++ b/src/com/android/messaging/ui/mediapicker/GalleryMediaChooser.java @@ -17,6 +17,8 @@ package com.android.messaging.ui.mediapicker; import android.Manifest; +import android.app.Activity; +import android.content.Intent; import android.content.pm.PackageManager; import android.database.Cursor; import android.database.MatrixCursor; @@ -35,6 +37,9 @@ import com.android.messaging.datamodel.data.GalleryGridItemData; import com.android.messaging.datamodel.data.MediaPickerData; import com.android.messaging.datamodel.data.MessagePartData; import com.android.messaging.datamodel.data.MediaPickerData.MediaPickerDataListener; +import com.android.messaging.datamodel.data.PendingAttachmentData; +import com.android.messaging.ui.UIIntents; +import com.android.messaging.ui.mediapicker.DocumentImagePicker.SelectionListener; import com.android.messaging.util.Assert; import com.android.messaging.util.OsUtil; @@ -47,9 +52,21 @@ class GalleryMediaChooser extends MediaChooser implements private GalleryGridView mGalleryGridView; private View mMissingPermissionView; + /** Handles picking a media from the document picker. */ + private DocumentImagePicker mDocumentImagePicker; + GalleryMediaChooser(final MediaPicker mediaPicker) { super(mediaPicker); mAdapter = new GalleryGridAdapter(Factory.get().getApplicationContext(), null); + mDocumentImagePicker = new DocumentImagePicker(mMediaPicker, + new SelectionListener() { + @Override + public void onDocumentSelected(final PendingAttachmentData data) { + if (mBindingRef.isBound()) { + mMediaPicker.dispatchPendingItemAdded(data); + } + } + }); } @Override @@ -148,7 +165,8 @@ class GalleryMediaChooser extends MediaChooser implements @Override public void onDocumentPickerItemClicked() { - mMediaPicker.launchDocumentPicker(); + // Launch an external picker to pick item from document picker as attachment. + mDocumentImagePicker.launchPicker(); } @Override @@ -230,4 +248,13 @@ class GalleryMediaChooser extends MediaChooser implements mGalleryGridView.setVisibility(granted ? View.VISIBLE : View.GONE); mMissingPermissionView.setVisibility(granted ? View.GONE : View.VISIBLE); } + + @Override + protected void onActivityResult( + final int requestCode, final int resultCode, final Intent data) { + if (requestCode == UIIntents.REQUEST_PICK_MEDIA_FROM_DOCUMENT_PICKER + && resultCode == Activity.RESULT_OK) { + mDocumentImagePicker.onActivityResult(requestCode, resultCode, data); + } + } } diff --git a/src/com/android/messaging/ui/mediapicker/MediaChooser.java b/src/com/android/messaging/ui/mediapicker/MediaChooser.java index ef4067c..0549e5b 100644 --- a/src/com/android/messaging/ui/mediapicker/MediaChooser.java +++ b/src/com/android/messaging/ui/mediapicker/MediaChooser.java @@ -18,6 +18,7 @@ package com.android.messaging.ui.mediapicker; import android.app.FragmentManager; import android.content.Context; +import android.content.Intent; import androidx.appcompat.app.ActionBar; import android.view.LayoutInflater; import android.view.Menu; @@ -203,6 +204,9 @@ abstract class MediaChooser extends BasePagerViewHolder public void stopTouchHandling() { } + protected void onActivityResult( + final int requestCode, final int resultCode, final Intent data) {} + @Override public int getConversationSelfSubId() { return mMediaPicker.getConversationSelfSubId(); diff --git a/src/com/android/messaging/ui/mediapicker/MediaPicker.java b/src/com/android/messaging/ui/mediapicker/MediaPicker.java index b8fce8f..c7faa33 100644 --- a/src/com/android/messaging/ui/mediapicker/MediaPicker.java +++ b/src/com/android/messaging/ui/mediapicker/MediaPicker.java @@ -16,7 +16,6 @@ package com.android.messaging.ui.mediapicker; - import android.app.Activity; import android.app.Fragment; import android.content.Context; @@ -48,7 +47,6 @@ import com.android.messaging.datamodel.data.PendingAttachmentData; import com.android.messaging.datamodel.data.DraftMessageData.DraftMessageSubscriptionDataProvider; import com.android.messaging.ui.BugleActionBarActivity; import com.android.messaging.ui.FixedViewPagerAdapter; -import com.android.messaging.ui.mediapicker.DocumentImagePicker.SelectionListener; import com.android.messaging.util.AccessibilityUtil; import com.android.messaging.util.Assert; import com.android.messaging.util.UiUtils; @@ -159,9 +157,6 @@ public class MediaPicker extends Fragment implements DraftMessageSubscriptionDat @VisibleForTesting final Binding<MediaPickerData> mBinding = BindingBase.createBinding(this); - /** Handles picking a media from the document picker. */ - private DocumentImagePicker mDocumentImagePicker; - /** Provides subscription-related data to access per-subscription configurations. */ private DraftMessageSubscriptionDataProvider mSubscriptionDataProvider; @@ -179,6 +174,7 @@ public class MediaPicker extends Fragment implements DraftMessageSubscriptionDat new CameraMediaChooser(this), new GalleryMediaChooser(this), new AudioMediaChooser(this), + new ContactMediaChooser(this), }; mOpen = false; @@ -203,15 +199,6 @@ public class MediaPicker extends Fragment implements DraftMessageSubscriptionDat public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding.getData().init(getLoaderManager()); - mDocumentImagePicker = new DocumentImagePicker(this, - new SelectionListener() { - @Override - public void onDocumentSelected(final PendingAttachmentData data) { - if (mBinding.isBound()) { - dispatchPendingItemAdded(data); - } - } - }); } @Override @@ -295,7 +282,7 @@ public class MediaPicker extends Fragment implements DraftMessageSubscriptionDat @Override public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { super.onActivityResult(requestCode, resultCode, data); - mDocumentImagePicker.onActivityResult(requestCode, resultCode, data); + mSelectedChooser.onActivityResult(requestCode, resultCode, data); } @Override @@ -710,13 +697,6 @@ public class MediaPicker extends Fragment implements DraftMessageSubscriptionDat mPagerAdapter.resetState(); } - /** - * Launch an external picker to pick item from document picker as attachment. - */ - public void launchDocumentPicker() { - mDocumentImagePicker.launchPicker(); - } - public ImmutableBindingRef<MediaPickerData> getMediaPickerDataBinding() { return BindingBase.createBindingReference(mBinding); } @@ -725,6 +705,7 @@ public class MediaPicker extends Fragment implements DraftMessageSubscriptionDat protected static final int LOCATION_PERMISSION_REQUEST_CODE = 2; protected static final int RECORD_AUDIO_PERMISSION_REQUEST_CODE = 3; protected static final int GALLERY_PERMISSION_REQUEST_CODE = 4; + protected static final int READ_CONTACT_PERMISSION_REQUEST_CODE = 5; @Override public void onRequestPermissionsResult( |