New interface to pick a contact as attachment

New ContactMediaChooser allows the user to pick a contact from contacts
apps as attachment.

Test: Manual

Change-Id: Idb00cd8a3164a3cac859947affd5cbcc7e41b8c2
Signed-off-by: Taesu Lee <taesu82.lee@samsung.com>
This commit is contained in:
Taesu Lee
2020-03-05 18:57:22 +09:00
parent 0fee5a1e35
commit 45d1e1d044
13 changed files with 296 additions and 46 deletions
+11 -1
View File
@@ -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";
@@ -166,12 +169,19 @@ 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.
*/
@@ -243,6 +243,19 @@ public class UIIntentsImpl extends UIIntents {
fragment.startActivityForResult(intent, REQUEST_PICK_MEDIA_FROM_DOCUMENT_PICKER);
}
@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) {
@@ -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);
}
});
}
}
}
}
}
@@ -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);
}
}
@@ -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);
}
}
}
@@ -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();
@@ -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(