Improved UX for DISALLOW_SET_USER_ICON restriction.

Modified popup menu, so that each item has a hint, why it is
blocked (in case the DISALLOW_SET_USER_ICON is set).

BUG:27914812
Change-Id: I1f891ffe725f383285d577cf47d89c294f2c3986
This commit is contained in:
Oleksandr Peletskyi
2016-04-01 21:40:58 +02:00
parent 36cce830b9
commit dccb31525a
3 changed files with 144 additions and 70 deletions

View File

@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2013, 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.
*/
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:textColor="?android:attr/textColorAlertDialogListItem"
android:gravity="center_vertical"
android:paddingStart="16dip"
android:paddingEnd="16dip"
android:ellipsize="marquee"
/>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2016, 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.
*/
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:gravity="center_vertical"
android:paddingStart="16dip"
android:paddingEnd="16dip">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorAlertDialogListItem"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:ellipsize="marquee"
android:layout_alignParentLeft="true" />
<ImageView
android:id="@+id/restricted_icon"
android:layout_width="@dimen/restricted_icon_size"
android:layout_height="@dimen/restricted_icon_size"
android:scaleType="centerInside"
android:src="@drawable/ic_info"
android:layout_alignParentRight="true"
android:visibility="gone" />
</RelativeLayout>

View File

@@ -32,6 +32,7 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.provider.ContactsContract.DisplayPhoto; import android.provider.ContactsContract.DisplayPhoto;
import android.provider.MediaStore; import android.provider.MediaStore;
@@ -40,13 +41,15 @@ import android.util.Log;
import android.view.Gravity; import android.view.Gravity;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListPopupWindow; import android.widget.ListPopupWindow;
import android.widget.TextView;
import com.android.settings.R; import com.android.settings.R;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.drawable.CircleFramedDrawable; import com.android.settingslib.drawable.CircleFramedDrawable;
import java.io.File; import java.io.File;
@@ -61,9 +64,6 @@ import java.util.List;
public class EditUserPhotoController { public class EditUserPhotoController {
private static final String TAG = "EditUserPhotoController"; private static final String TAG = "EditUserPhotoController";
private static final int POPUP_LIST_ITEM_ID_CHOOSE_PHOTO = 1;
private static final int POPUP_LIST_ITEM_ID_TAKE_PHOTO = 2;
// It seems that this class generates custom request codes and they may // It seems that this class generates custom request codes and they may
// collide with ours, these values are very unlikely to have a conflict. // collide with ours, these values are very unlikely to have a conflict.
private static final int REQUEST_CODE_CHOOSE_PHOTO = 1001; private static final int REQUEST_CODE_CHOOSE_PHOTO = 1001;
@@ -100,10 +100,6 @@ public class EditUserPhotoController {
showUpdatePhotoPopup(); showUpdatePhotoPopup();
} }
}); });
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
if (um.hasUserRestriction(UserManager.DISALLOW_SET_USER_ICON)) {
mImageView.setEnabled(false);
}
mNewUserPhotoBitmap = bitmap; mNewUserPhotoBitmap = bitmap;
mNewUserPhotoDrawable = drawable; mNewUserPhotoDrawable = drawable;
} }
@@ -142,19 +138,31 @@ public class EditUserPhotoController {
return; return;
} }
Context context = mImageView.getContext(); final Context context = mImageView.getContext();
final List<EditUserPhotoController.AdapterItem> items = new ArrayList<EditUserPhotoController.AdapterItem>(); final List<EditUserPhotoController.RestrictedMenuItem> items = new ArrayList<>();
if (canTakePhoto()) { if (canTakePhoto) {
String title = mImageView.getContext().getString( R.string.user_image_take_photo); final String title = context.getString(R.string.user_image_take_photo);
EditUserPhotoController.AdapterItem item = new AdapterItem(title, POPUP_LIST_ITEM_ID_TAKE_PHOTO); final Runnable action = new Runnable() {
items.add(item); @Override
public void run() {
takePhoto();
}
};
items.add(new RestrictedMenuItem(context, title, UserManager.DISALLOW_SET_USER_ICON,
action));
} }
if (canChoosePhoto) { if (canChoosePhoto) {
String title = context.getString(R.string.user_image_choose_photo); final String title = context.getString(R.string.user_image_choose_photo);
EditUserPhotoController.AdapterItem item = new AdapterItem(title, POPUP_LIST_ITEM_ID_CHOOSE_PHOTO); final Runnable action = new Runnable() {
items.add(item); @Override
public void run() {
choosePhoto();
}
};
items.add(new RestrictedMenuItem(context, title, UserManager.DISALLOW_SET_USER_ICON,
action));
} }
final ListPopupWindow listPopupWindow = new ListPopupWindow(context); final ListPopupWindow listPopupWindow = new ListPopupWindow(context);
@@ -162,10 +170,7 @@ public class EditUserPhotoController {
listPopupWindow.setAnchorView(mImageView); listPopupWindow.setAnchorView(mImageView);
listPopupWindow.setModal(true); listPopupWindow.setModal(true);
listPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED); listPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
listPopupWindow.setAdapter(new RestrictedPopupMenuAdapter(context, items));
ListAdapter adapter = new ArrayAdapter<EditUserPhotoController.AdapterItem>(context,
R.layout.edit_user_photo_popup_item, items);
listPopupWindow.setAdapter(adapter);
final int width = Math.max(mImageView.getWidth(), context.getResources() final int width = Math.max(mImageView.getWidth(), context.getResources()
.getDimensionPixelSize(R.dimen.update_user_photo_popup_min_width)); .getDimensionPixelSize(R.dimen.update_user_photo_popup_min_width));
@@ -175,17 +180,10 @@ public class EditUserPhotoController {
listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() { listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
EditUserPhotoController.AdapterItem item = items.get(position); listPopupWindow.dismiss();
switch (item.id) { final RestrictedMenuItem item =
case POPUP_LIST_ITEM_ID_CHOOSE_PHOTO: { (RestrictedMenuItem) parent.getAdapter().getItem(position);
choosePhoto(); item.doAction();
listPopupWindow.dismiss();
} break;
case POPUP_LIST_ITEM_ID_TAKE_PHOTO: {
takePhoto();
listPopupWindow.dismiss();
} break;
}
} }
}); });
@@ -363,18 +361,82 @@ public class EditUserPhotoController {
new File(mContext.getCacheDir(), NEW_USER_PHOTO_FILE_NAME).delete(); new File(mContext.getCacheDir(), NEW_USER_PHOTO_FILE_NAME).delete();
} }
private static final class AdapterItem { private static final class RestrictedMenuItem {
final String title; private final Context mContext;
final int id; private final String mTitle;
private final Runnable mAction;
private final RestrictedLockUtils.EnforcedAdmin mAdmin;
// Restriction may be set by system or something else via UserManager.setUserRestriction().
private final boolean mIsRestrictedByBase;
public AdapterItem(String title, int id) { /**
this.title = title; * The menu item, used for popup menu. Any element of such a menu can be disabled by admin.
this.id = id; * @param context A context.
* @param title The title of the menu item.
* @param restriction The restriction, that if is set, blocks the menu item.
* @param action The action on menu item click.
*/
public RestrictedMenuItem(Context context, String title, String restriction,
Runnable action) {
mContext = context;
mTitle = title;
mAction = action;
final int myUserId = UserHandle.myUserId();
mAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(context,
restriction, myUserId);
mIsRestrictedByBase = RestrictedLockUtils.hasBaseUserRestriction(mContext,
restriction, myUserId);
} }
@Override @Override
public String toString() { public String toString() {
return title; return mTitle;
}
final void doAction() {
if (isRestrictedByBase()) {
return;
}
if (isRestrictedByAdmin()) {
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, mAdmin);
return;
}
mAction.run();
}
final boolean isRestrictedByAdmin() {
return mAdmin != null;
}
final boolean isRestrictedByBase() {
return mIsRestrictedByBase;
}
}
/**
* Provide this adapter to ListPopupWindow.setAdapter() to have a popup window menu, where
* any element can be restricted by admin (profile owner or device owner).
*/
private static final class RestrictedPopupMenuAdapter extends ArrayAdapter<RestrictedMenuItem> {
public RestrictedPopupMenuAdapter(Context context, List<RestrictedMenuItem> items) {
super(context, R.layout.restricted_popup_menu_item, R.id.text, items);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View view = super.getView(position, convertView, parent);
final RestrictedMenuItem item = getItem(position);
final TextView text = (TextView) view.findViewById(R.id.text);
final ImageView image = (ImageView) view.findViewById(R.id.restricted_icon);
text.setEnabled(!item.isRestrictedByAdmin() && !item.isRestrictedByBase());
image.setVisibility(item.isRestrictedByAdmin() && !item.isRestrictedByBase() ?
ImageView.VISIBLE : ImageView.GONE);
return view;
} }
} }
} }