Single-user restrictions
New restrictions panel for restricting list of available apps for the user. Apps that support restrictions can also be configured here. Restrictions screen is PIN protected and will ask you to create a PIN the first time you use it. Change-Id: I7a5267df4272521ad80e6a8b6a18932d07179eb8
This commit is contained in:
@@ -4468,6 +4468,15 @@
|
|||||||
<!-- Warning message title for global font change [CHAR LIMIT=40] -->
|
<!-- Warning message title for global font change [CHAR LIMIT=40] -->
|
||||||
<string name="global_font_change_title">Change font size</string>
|
<string name="global_font_change_title">Change font size</string>
|
||||||
|
|
||||||
|
<!-- Restrictions settings --><skip/>
|
||||||
|
|
||||||
|
<!-- Restriction settings title [CHAR LIMIT=35] -->
|
||||||
|
<string name="restriction_settings_title">Restrictions</string>
|
||||||
|
<!-- Restrictions screen - reset menu to reset to unrestricted [CHAR LIMIT=25] -->
|
||||||
|
<string name="restriction_menu_reset">Remove restrictions</string>
|
||||||
|
<!-- Restrictions screen - menu label to change restrictions pin [CHAR LIMIT=25] -->
|
||||||
|
<string name="restriction_menu_change_pin">Change PIN</string>
|
||||||
|
|
||||||
<!-- Label for are-notifications-enabled checkbox in app details [CHAR LIMIT=20] -->
|
<!-- Label for are-notifications-enabled checkbox in app details [CHAR LIMIT=20] -->
|
||||||
<string name="app_notifications_switch_label">Show notifications</string>
|
<string name="app_notifications_switch_label">Show notifications</string>
|
||||||
|
|
||||||
|
@@ -97,6 +97,13 @@
|
|||||||
android:title="@string/applications_settings"
|
android:title="@string/applications_settings"
|
||||||
android:id="@+id/application_settings" />
|
android:id="@+id/application_settings" />
|
||||||
|
|
||||||
|
<!-- Manage restrictions -->
|
||||||
|
<header
|
||||||
|
android:fragment="com.android.settings.users.RestrictionSettings"
|
||||||
|
android:icon="@drawable/ic_settings_multiuser"
|
||||||
|
android:title="@string/restriction_settings_title"
|
||||||
|
android:id="@+id/restriction_settings" />
|
||||||
|
|
||||||
<!-- Manage users -->
|
<!-- Manage users -->
|
||||||
<header
|
<header
|
||||||
android:fragment="com.android.settings.users.UserSettings"
|
android:fragment="com.android.settings.users.UserSettings"
|
||||||
|
@@ -116,6 +116,7 @@ public class Settings extends PreferenceActivity
|
|||||||
R.id.location_settings,
|
R.id.location_settings,
|
||||||
R.id.security_settings,
|
R.id.security_settings,
|
||||||
R.id.language_settings,
|
R.id.language_settings,
|
||||||
|
R.id.restriction_settings,
|
||||||
R.id.user_settings,
|
R.id.user_settings,
|
||||||
R.id.account_settings,
|
R.id.account_settings,
|
||||||
R.id.account_add,
|
R.id.account_add,
|
||||||
@@ -486,6 +487,10 @@ public class Settings extends PreferenceActivity
|
|||||||
if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
|
if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
|
||||||
target.remove(i);
|
target.remove(i);
|
||||||
}
|
}
|
||||||
|
} else if (id == R.id.restriction_settings) {
|
||||||
|
if (um.isLinkedUser()) {
|
||||||
|
target.remove(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < target.size() && target.get(i) == header
|
if (i < target.size() && target.get(i) == header
|
||||||
|
@@ -17,14 +17,10 @@
|
|||||||
package com.android.settings.users;
|
package com.android.settings.users;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.AppGlobals;
|
import android.app.AppGlobals;
|
||||||
import android.app.Dialog;
|
|
||||||
import android.app.Fragment;
|
|
||||||
import android.appwidget.AppWidgetManager;
|
import android.appwidget.AppWidgetManager;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.RestrictionEntry;
|
import android.content.RestrictionEntry;
|
||||||
@@ -34,16 +30,12 @@ import android.content.pm.PackageInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.pm.UserInfo;
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.graphics.ColorFilter;
|
import android.graphics.ColorFilter;
|
||||||
import android.graphics.ColorMatrix;
|
import android.graphics.ColorMatrix;
|
||||||
import android.graphics.ColorMatrixColorFilter;
|
import android.graphics.ColorMatrixColorFilter;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -58,33 +50,20 @@ import android.preference.Preference.OnPreferenceChangeListener;
|
|||||||
import android.preference.Preference.OnPreferenceClickListener;
|
import android.preference.Preference.OnPreferenceClickListener;
|
||||||
import android.preference.PreferenceGroup;
|
import android.preference.PreferenceGroup;
|
||||||
import android.preference.SwitchPreference;
|
import android.preference.SwitchPreference;
|
||||||
import android.provider.ContactsContract.DisplayPhoto;
|
|
||||||
import android.provider.MediaStore;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.inputmethod.InputMethod;
|
|
||||||
import android.view.inputmethod.InputMethodInfo;
|
import android.view.inputmethod.InputMethodInfo;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.ListAdapter;
|
|
||||||
import android.widget.ListPopupWindow;
|
|
||||||
import android.widget.Switch;
|
import android.widget.Switch;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsPreferenceFragment;
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@@ -103,13 +82,10 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
private static final String PKG_PREFIX = "pkg_";
|
private static final String PKG_PREFIX = "pkg_";
|
||||||
private static final String KEY_USER_INFO = "user_info";
|
|
||||||
|
|
||||||
private static final int DIALOG_ID_EDIT_USER_INFO = 1;
|
protected PackageManager mPackageManager;
|
||||||
|
protected UserManager mUserManager;
|
||||||
private PackageManager mPackageManager;
|
protected UserHandle mUser;
|
||||||
private UserManager mUserManager;
|
|
||||||
private UserHandle mUser;
|
|
||||||
|
|
||||||
private PreferenceGroup mAppList;
|
private PreferenceGroup mAppList;
|
||||||
|
|
||||||
@@ -123,28 +99,21 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
/** Key for extra passed in from calling fragment to indicate if this is a newly created user */
|
/** Key for extra passed in from calling fragment to indicate if this is a newly created user */
|
||||||
public static final String EXTRA_NEW_USER = "new_user";
|
public static final String EXTRA_NEW_USER = "new_user";
|
||||||
|
|
||||||
private static final String KEY_SAVED_PHOTO = "pending_photo";
|
|
||||||
|
|
||||||
HashMap<String,Boolean> mSelectedPackages = new HashMap<String,Boolean>();
|
HashMap<String,Boolean> mSelectedPackages = new HashMap<String,Boolean>();
|
||||||
private boolean mFirstTime = true;
|
private boolean mFirstTime = true;
|
||||||
private boolean mNewUser;
|
private boolean mNewUser;
|
||||||
private boolean mAppListChanged;
|
private boolean mAppListChanged;
|
||||||
|
protected boolean mRestrictedProfile;
|
||||||
|
|
||||||
|
private static final int CUSTOM_REQUEST_CODE_START = 1000;
|
||||||
|
private int mCustomRequestCode = CUSTOM_REQUEST_CODE_START;
|
||||||
|
|
||||||
private int mCustomRequestCode;
|
|
||||||
private HashMap<Integer, AppRestrictionsPreference> mCustomRequestMap =
|
private HashMap<Integer, AppRestrictionsPreference> mCustomRequestMap =
|
||||||
new HashMap<Integer,AppRestrictionsPreference>();
|
new HashMap<Integer,AppRestrictionsPreference>();
|
||||||
private View mHeaderView;
|
|
||||||
private ImageView mUserIconView;
|
|
||||||
private TextView mUserNameView;
|
|
||||||
|
|
||||||
private List<SelectableAppInfo> mVisibleApps;
|
private List<SelectableAppInfo> mVisibleApps;
|
||||||
private List<ApplicationInfo> mUserApps;
|
private List<ApplicationInfo> mUserApps;
|
||||||
|
|
||||||
private Dialog mEditUserInfoDialog;
|
|
||||||
|
|
||||||
private EditUserPhotoController mEditUserPhotoController;
|
|
||||||
private Bitmap mSavedPhoto;
|
|
||||||
|
|
||||||
private BroadcastReceiver mUserBackgrounding = new BroadcastReceiver() {
|
private BroadcastReceiver mUserBackgrounding = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
@@ -153,7 +122,7 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
// have been scheduled during user startup.
|
// have been scheduled during user startup.
|
||||||
if (mAppListChanged) {
|
if (mAppListChanged) {
|
||||||
if (DEBUG) Log.d(TAG, "User backgrounding, update app list");
|
if (DEBUG) Log.d(TAG, "User backgrounding, update app list");
|
||||||
updateUserAppList();
|
applyUserAppsStates();
|
||||||
if (DEBUG) Log.d(TAG, "User backgrounding, done updating app list");
|
if (DEBUG) Log.d(TAG, "User backgrounding, done updating app list");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,7 +149,6 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
boolean panelOpen;
|
boolean panelOpen;
|
||||||
private boolean immutable;
|
private boolean immutable;
|
||||||
List<Preference> childPreferences = new ArrayList<Preference>();
|
List<Preference> childPreferences = new ArrayList<Preference>();
|
||||||
private SelectableAppInfo appInfo;
|
|
||||||
private final ColorFilter grayscaleFilter;
|
private final ColorFilter grayscaleFilter;
|
||||||
|
|
||||||
AppRestrictionsPreference(Context context, OnClickListener listener) {
|
AppRestrictionsPreference(Context context, OnClickListener listener) {
|
||||||
@@ -221,10 +189,6 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
return immutable;
|
return immutable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSelectableAppInfo(SelectableAppInfo appInfo) {
|
|
||||||
this.appInfo = appInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
RestrictionEntry getRestriction(String key) {
|
RestrictionEntry getRestriction(String key) {
|
||||||
if (restrictions == null) return null;
|
if (restrictions == null) return null;
|
||||||
for (RestrictionEntry entry : restrictions) {
|
for (RestrictionEntry entry : restrictions) {
|
||||||
@@ -270,65 +234,44 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected void init(Bundle icicle) {
|
||||||
public void onCreate(Bundle icicle) {
|
|
||||||
super.onCreate(icicle);
|
|
||||||
|
|
||||||
if (icicle != null) {
|
if (icicle != null) {
|
||||||
mUser = new UserHandle(icicle.getInt(EXTRA_USER_ID));
|
mUser = new UserHandle(icicle.getInt(EXTRA_USER_ID));
|
||||||
mSavedPhoto = (Bitmap) icicle.getParcelable(KEY_SAVED_PHOTO);
|
|
||||||
} else {
|
} else {
|
||||||
Bundle args = getArguments();
|
Bundle args = getArguments();
|
||||||
|
if (args != null) {
|
||||||
if (args.containsKey(EXTRA_USER_ID)) {
|
if (args.containsKey(EXTRA_USER_ID)) {
|
||||||
mUser = new UserHandle(args.getInt(EXTRA_USER_ID));
|
mUser = new UserHandle(args.getInt(EXTRA_USER_ID));
|
||||||
}
|
}
|
||||||
mNewUser = args.getBoolean(EXTRA_NEW_USER, false);
|
mNewUser = args.getBoolean(EXTRA_NEW_USER, false);
|
||||||
}
|
}
|
||||||
mPackageManager = getActivity().getPackageManager();
|
|
||||||
mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
|
|
||||||
addPreferencesFromResource(R.xml.app_restrictions);
|
|
||||||
mAppList = getPreferenceScreen();
|
|
||||||
setHasOptionsMenu(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
if (mUser == null) {
|
||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
mUser = android.os.Process.myUserHandle();
|
||||||
if (mHeaderView == null) {
|
|
||||||
mHeaderView = LayoutInflater.from(getActivity()).inflate(
|
|
||||||
R.layout.user_info_header, null);
|
|
||||||
((ViewGroup) getListView().getParent()).addView(mHeaderView, 0);
|
|
||||||
mHeaderView.setOnClickListener(this);
|
|
||||||
mUserIconView = (ImageView) mHeaderView.findViewById(android.R.id.icon);
|
|
||||||
mUserNameView = (TextView) mHeaderView.findViewById(android.R.id.title);
|
|
||||||
getListView().setFastScrollEnabled(true);
|
|
||||||
}
|
}
|
||||||
// This is going to bind the preferences.
|
|
||||||
super.onActivityCreated(savedInstanceState);
|
mPackageManager = getActivity().getPackageManager();
|
||||||
|
mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
|
||||||
|
mRestrictedProfile = mUserManager.getUserInfo(mUser.getIdentifier()).isRestricted();
|
||||||
|
|
||||||
|
addPreferencesFromResource(R.xml.app_restrictions);
|
||||||
|
mAppList = getAppPreferenceGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putInt(EXTRA_USER_ID, mUser.getIdentifier());
|
outState.putInt(EXTRA_USER_ID, mUser.getIdentifier());
|
||||||
if (mEditUserInfoDialog != null && mEditUserInfoDialog.isShowing()
|
|
||||||
&& mEditUserPhotoController != null) {
|
|
||||||
outState.putParcelable(KEY_SAVED_PHOTO,
|
|
||||||
mEditUserPhotoController.getNewUserPhotoBitmap());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
getActivity().registerReceiver(mUserBackgrounding,
|
getActivity().registerReceiver(mUserBackgrounding,
|
||||||
new IntentFilter(Intent.ACTION_USER_BACKGROUND));
|
new IntentFilter(Intent.ACTION_USER_BACKGROUND));
|
||||||
mAppListChanged = false;
|
mAppListChanged = false;
|
||||||
new AppLoadingTask().execute((Void[]) null);
|
new AppLoadingTask().execute((Void[]) null);
|
||||||
|
|
||||||
UserInfo info = mUserManager.getUserInfo(mUser.getIdentifier());
|
|
||||||
((TextView) mHeaderView.findViewById(android.R.id.title)).setText(info.name);
|
|
||||||
((ImageView) mHeaderView.findViewById(android.R.id.icon)).setImageDrawable(
|
|
||||||
getCircularUserIcon());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
@@ -338,25 +281,33 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
if (mAppListChanged) {
|
if (mAppListChanged) {
|
||||||
new Thread() {
|
new Thread() {
|
||||||
public void run() {
|
public void run() {
|
||||||
updateUserAppList();
|
applyUserAppsStates();
|
||||||
}
|
}
|
||||||
}.start();
|
}.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable getCircularUserIcon() {
|
protected PreferenceGroup getAppPreferenceGroup() {
|
||||||
|
return getPreferenceScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Drawable getCircularUserIcon() {
|
||||||
Bitmap userIcon = mUserManager.getUserIcon(mUser.getIdentifier());
|
Bitmap userIcon = mUserManager.getUserIcon(mUser.getIdentifier());
|
||||||
CircleFramedDrawable circularIcon =
|
CircleFramedDrawable circularIcon =
|
||||||
CircleFramedDrawable.getInstance(this.getActivity(), userIcon);
|
CircleFramedDrawable.getInstance(this.getActivity(), userIcon);
|
||||||
return circularIcon;
|
return circularIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateUserAppList() {
|
protected void clearSelectedApps() {
|
||||||
|
mSelectedPackages.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyUserAppsStates() {
|
||||||
IPackageManager ipm = IPackageManager.Stub.asInterface(
|
IPackageManager ipm = IPackageManager.Stub.asInterface(
|
||||||
ServiceManager.getService("package"));
|
ServiceManager.getService("package"));
|
||||||
final int userId = mUser.getIdentifier();
|
final int userId = mUser.getIdentifier();
|
||||||
if (!mUserManager.getUserInfo(userId).isRestricted()) {
|
if (!mUserManager.getUserInfo(userId).isRestricted() && userId != UserHandle.myUserId()) {
|
||||||
Log.e(TAG, "Cannot apply application restrictions on a regular user!");
|
Log.e(TAG, "Cannot apply application restrictions on another user!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (Map.Entry<String,Boolean> entry : mSelectedPackages.entrySet()) {
|
for (Map.Entry<String,Boolean> entry : mSelectedPackages.entrySet()) {
|
||||||
@@ -364,13 +315,21 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
if (entry.getValue()) {
|
if (entry.getValue()) {
|
||||||
// Enable selected apps
|
// Enable selected apps
|
||||||
try {
|
try {
|
||||||
ApplicationInfo info = ipm.getApplicationInfo(packageName, 0, userId);
|
ApplicationInfo info = ipm.getApplicationInfo(packageName,
|
||||||
|
PackageManager.GET_UNINSTALLED_PACKAGES, userId);
|
||||||
if (info == null || info.enabled == false) {
|
if (info == null || info.enabled == false) {
|
||||||
ipm.installExistingPackageAsUser(packageName, mUser.getIdentifier());
|
ipm.installExistingPackageAsUser(packageName, mUser.getIdentifier());
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Installing " + packageName);
|
Log.d(TAG, "Installing " + packageName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (info != null && (info.flags&ApplicationInfo.FLAG_BLOCKED) != 0
|
||||||
|
&& (info.flags&ApplicationInfo.FLAG_INSTALLED) != 0) {
|
||||||
|
ipm.setApplicationBlockedSettingAsUser(packageName, false, userId);
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Unblocking " + packageName);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (RemoteException re) {
|
} catch (RemoteException re) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -378,11 +337,18 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
try {
|
try {
|
||||||
ApplicationInfo info = ipm.getApplicationInfo(packageName, 0, userId);
|
ApplicationInfo info = ipm.getApplicationInfo(packageName, 0, userId);
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
|
if (mRestrictedProfile) {
|
||||||
ipm.deletePackageAsUser(entry.getKey(), null, mUser.getIdentifier(),
|
ipm.deletePackageAsUser(entry.getKey(), null, mUser.getIdentifier(),
|
||||||
PackageManager.DELETE_SYSTEM_APP);
|
PackageManager.DELETE_SYSTEM_APP);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Uninstalling " + packageName);
|
Log.d(TAG, "Uninstalling " + packageName);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ipm.setApplicationBlockedSettingAsUser(packageName, true, userId);
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Blocking " + packageName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (RemoteException re) {
|
} catch (RemoteException re) {
|
||||||
}
|
}
|
||||||
@@ -441,7 +407,7 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
if (getActivity() == null) return;
|
if (getActivity() == null) return;
|
||||||
final PackageManager pm = mPackageManager;
|
final PackageManager pm = mPackageManager;
|
||||||
List<ResolveInfo> launchableApps = pm.queryIntentActivities(intent,
|
List<ResolveInfo> launchableApps = pm.queryIntentActivities(intent,
|
||||||
PackageManager.GET_DISABLED_COMPONENTS);
|
PackageManager.GET_DISABLED_COMPONENTS | PackageManager.GET_UNINSTALLED_PACKAGES);
|
||||||
for (ResolveInfo app : launchableApps) {
|
for (ResolveInfo app : launchableApps) {
|
||||||
if (app.activityInfo != null && app.activityInfo.applicationInfo != null) {
|
if (app.activityInfo != null && app.activityInfo.applicationInfo != null) {
|
||||||
int flags = app.activityInfo.applicationInfo.flags;
|
int flags = app.activityInfo.applicationInfo.flags;
|
||||||
@@ -502,8 +468,12 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
Intent widgetIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
Intent widgetIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
||||||
addSystemApps(mVisibleApps, widgetIntent, excludePackages);
|
addSystemApps(mVisibleApps, widgetIntent, excludePackages);
|
||||||
|
|
||||||
List<ApplicationInfo> installedApps = pm.getInstalledApplications(0);
|
List<ApplicationInfo> installedApps = pm.getInstalledApplications(
|
||||||
|
PackageManager.GET_UNINSTALLED_PACKAGES);
|
||||||
for (ApplicationInfo app : installedApps) {
|
for (ApplicationInfo app : installedApps) {
|
||||||
|
// If it's not installed, skip
|
||||||
|
if ((app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) continue;
|
||||||
|
|
||||||
if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0
|
if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0
|
||||||
&& (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {
|
&& (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {
|
||||||
// Downloaded app
|
// Downloaded app
|
||||||
@@ -519,7 +489,8 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
// If it's a system app that requires an account and doesn't see restricted
|
// If it's a system app that requires an account and doesn't see restricted
|
||||||
// accounts, mark for removal. It might get shown in the UI if it has an icon
|
// accounts, mark for removal. It might get shown in the UI if it has an icon
|
||||||
// but will still be marked as false and immutable.
|
// but will still be marked as false and immutable.
|
||||||
if (pi.requiredAccountType != null && pi.restrictedAccountType == null) {
|
if (mRestrictedProfile
|
||||||
|
&& pi.requiredAccountType != null && pi.restrictedAccountType == null) {
|
||||||
mSelectedPackages.put(app.packageName, false);
|
mSelectedPackages.put(app.packageName, false);
|
||||||
}
|
}
|
||||||
} catch (NameNotFoundException re) {
|
} catch (NameNotFoundException re) {
|
||||||
@@ -530,12 +501,14 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
mUserApps = null;
|
mUserApps = null;
|
||||||
try {
|
try {
|
||||||
mUserApps = ipm.getInstalledApplications(
|
mUserApps = ipm.getInstalledApplications(
|
||||||
0, mUser.getIdentifier()).getList();
|
PackageManager.GET_UNINSTALLED_PACKAGES, mUser.getIdentifier()).getList();
|
||||||
} catch (RemoteException re) {
|
} catch (RemoteException re) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mUserApps != null) {
|
if (mUserApps != null) {
|
||||||
for (ApplicationInfo app : mUserApps) {
|
for (ApplicationInfo app : mUserApps) {
|
||||||
|
if ((app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) continue;
|
||||||
|
|
||||||
if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0
|
if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0
|
||||||
&& (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {
|
&& (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {
|
||||||
// Downloaded app
|
// Downloaded app
|
||||||
@@ -576,6 +549,14 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isAppEnabledForUser(PackageInfo pi) {
|
||||||
|
if (pi == null) return false;
|
||||||
|
final int flags = pi.applicationInfo.flags;
|
||||||
|
// Return true if it is installed and not blocked
|
||||||
|
return ((flags&ApplicationInfo.FLAG_INSTALLED) != 0
|
||||||
|
&& (flags&ApplicationInfo.FLAG_BLOCKED) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
private void populateApps() {
|
private void populateApps() {
|
||||||
final Context context = getActivity();
|
final Context context = getActivity();
|
||||||
if (context == null) return;
|
if (context == null) return;
|
||||||
@@ -606,13 +587,10 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
p.setOnPreferenceClickListener(this);
|
p.setOnPreferenceClickListener(this);
|
||||||
PackageInfo pi = null;
|
PackageInfo pi = null;
|
||||||
try {
|
try {
|
||||||
pi = pm.getPackageInfo(packageName, 0);
|
pi = ipm.getPackageInfo(packageName,
|
||||||
} catch (NameNotFoundException re) {
|
PackageManager.GET_UNINSTALLED_PACKAGES, mUser.getIdentifier());
|
||||||
try {
|
|
||||||
pi = ipm.getPackageInfo(packageName, 0, mUser.getIdentifier());
|
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (pi != null && pi.requiredForAllUsers) {
|
if (pi != null && pi.requiredForAllUsers) {
|
||||||
p.setChecked(true);
|
p.setChecked(true);
|
||||||
p.setImmutable(true);
|
p.setImmutable(true);
|
||||||
@@ -623,15 +601,16 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
if (hasSettings) {
|
if (hasSettings) {
|
||||||
requestRestrictionsForApp(packageName, p);
|
requestRestrictionsForApp(packageName, p);
|
||||||
}
|
}
|
||||||
} else if (!mNewUser && appInfoListHasPackage(mUserApps, packageName)) {
|
} else if (!mNewUser && isAppEnabledForUser(pi)) { /*appInfoListHasPackage(mUserApps, packageName)*/
|
||||||
p.setChecked(true);
|
p.setChecked(true);
|
||||||
}
|
}
|
||||||
if (pi.requiredAccountType != null && pi.restrictedAccountType == null) {
|
if (mRestrictedProfile
|
||||||
|
&& pi.requiredAccountType != null && pi.restrictedAccountType == null) {
|
||||||
p.setChecked(false);
|
p.setChecked(false);
|
||||||
p.setImmutable(true);
|
p.setImmutable(true);
|
||||||
p.setSummary(R.string.app_not_supported_in_limited);
|
p.setSummary(R.string.app_not_supported_in_limited);
|
||||||
}
|
}
|
||||||
if (pi.restrictedAccountType != null) {
|
if (mRestrictedProfile && pi.restrictedAccountType != null) {
|
||||||
p.setSummary(R.string.app_sees_restricted_accounts);
|
p.setSummary(R.string.app_sees_restricted_accounts);
|
||||||
}
|
}
|
||||||
if (app.masterEntry != null) {
|
if (app.masterEntry != null) {
|
||||||
@@ -644,7 +623,6 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
} else {
|
} else {
|
||||||
p.setOrder(MAX_APP_RESTRICTIONS * (i + 2));
|
p.setOrder(MAX_APP_RESTRICTIONS * (i + 2));
|
||||||
}
|
}
|
||||||
p.setSelectableAppInfo(app);
|
|
||||||
mSelectedPackages.put(packageName, p.isChecked());
|
mSelectedPackages.put(packageName, p.isChecked());
|
||||||
mAppListChanged = true;
|
mAppListChanged = true;
|
||||||
i++;
|
i++;
|
||||||
@@ -654,7 +632,7 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
// to avoid taking the hit in onPause(), which can cause race conditions on user switch.
|
// to avoid taking the hit in onPause(), which can cause race conditions on user switch.
|
||||||
if (mNewUser && mFirstTime) {
|
if (mNewUser && mFirstTime) {
|
||||||
mFirstTime = false;
|
mFirstTime = false;
|
||||||
updateUserAppList();
|
applyUserAppsStates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -677,15 +655,6 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean appInfoListHasPackage(List<ApplicationInfo> apps, String packageName) {
|
|
||||||
for (ApplicationInfo info : apps) {
|
|
||||||
if (info.packageName.equals(packageName)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateAllEntries(String prefKey, boolean checked) {
|
private void updateAllEntries(String prefKey, boolean checked) {
|
||||||
for (int i = 0; i < mAppList.getPreferenceCount(); i++) {
|
for (int i = 0; i < mAppList.getPreferenceCount(); i++) {
|
||||||
Preference pref = mAppList.getPreference(i);
|
Preference pref = mAppList.getPreference(i);
|
||||||
@@ -699,9 +668,7 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (v == mHeaderView) {
|
if (v.getTag() instanceof AppRestrictionsPreference) {
|
||||||
showDialog(DIALOG_ID_EDIT_USER_INFO);
|
|
||||||
} else if (v.getTag() instanceof AppRestrictionsPreference) {
|
|
||||||
AppRestrictionsPreference pref = (AppRestrictionsPreference) v.getTag();
|
AppRestrictionsPreference pref = (AppRestrictionsPreference) v.getTag();
|
||||||
if (v.getId() == R.id.app_restrictions_settings) {
|
if (v.getId() == R.id.app_restrictions_settings) {
|
||||||
toggleAppPanel(pref);
|
toggleAppPanel(pref);
|
||||||
@@ -746,8 +713,6 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
listPref.setSummary(readable);
|
listPref.setSummary(readable);
|
||||||
break;
|
break;
|
||||||
case RestrictionEntry.TYPE_MULTI_SELECT:
|
case RestrictionEntry.TYPE_MULTI_SELECT:
|
||||||
MultiSelectListPreference msListPref =
|
|
||||||
(MultiSelectListPreference) preference;
|
|
||||||
Set<String> set = (Set<String>) newValue;
|
Set<String> set = (Set<String>) newValue;
|
||||||
String [] selectedValues = new String[set.size()];
|
String [] selectedValues = new String[set.size()];
|
||||||
set.toArray(selectedValues);
|
set.toArray(selectedValues);
|
||||||
@@ -936,11 +901,6 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
if (mEditUserInfoDialog != null && mEditUserInfoDialog.isShowing()
|
|
||||||
&& mEditUserPhotoController.onActivityResult(requestCode, resultCode, data)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AppRestrictionsPreference pref = mCustomRequestMap.get(requestCode);
|
AppRestrictionsPreference pref = mCustomRequestMap.get(requestCode);
|
||||||
if (pref == null) {
|
if (pref == null) {
|
||||||
Log.w(TAG, "Unknown requestCode " + requestCode);
|
Log.w(TAG, "Unknown requestCode " + requestCode);
|
||||||
@@ -992,317 +952,4 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(int dialogId) {
|
|
||||||
if (dialogId == DIALOG_ID_EDIT_USER_INFO) {
|
|
||||||
if (mEditUserInfoDialog != null) {
|
|
||||||
return mEditUserInfoDialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
|
||||||
View content = inflater.inflate(R.layout.edit_user_info_dialog_content, null);
|
|
||||||
|
|
||||||
UserInfo info = mUserManager.getUserInfo(mUser.getIdentifier());
|
|
||||||
|
|
||||||
final EditText userNameView = (EditText) content.findViewById(R.id.user_name);
|
|
||||||
userNameView.setText(info.name);
|
|
||||||
|
|
||||||
final ImageView userPhotoView = (ImageView) content.findViewById(R.id.user_photo);
|
|
||||||
Drawable drawable = null;
|
|
||||||
if (mSavedPhoto != null) {
|
|
||||||
drawable = CircleFramedDrawable.getInstance(getActivity(), mSavedPhoto);
|
|
||||||
} else {
|
|
||||||
drawable = mUserIconView.getDrawable();
|
|
||||||
if (drawable == null) {
|
|
||||||
drawable = getCircularUserIcon();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
userPhotoView.setImageDrawable(drawable);
|
|
||||||
|
|
||||||
mEditUserPhotoController = new EditUserPhotoController(this, userPhotoView,
|
|
||||||
mSavedPhoto, drawable);
|
|
||||||
|
|
||||||
mEditUserInfoDialog = new AlertDialog.Builder(getActivity())
|
|
||||||
.setTitle(R.string.profile_info_settings_title)
|
|
||||||
.setIconAttribute(R.drawable.ic_settings_multiuser)
|
|
||||||
.setView(content)
|
|
||||||
.setCancelable(true)
|
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
|
||||||
// Update the name if changed.
|
|
||||||
CharSequence userName = userNameView.getText();
|
|
||||||
if (!TextUtils.isEmpty(userName)) {
|
|
||||||
CharSequence oldUserName = mUserNameView.getText();
|
|
||||||
if (oldUserName == null
|
|
||||||
|| !userName.toString().equals(oldUserName.toString())) {
|
|
||||||
((TextView) mHeaderView.findViewById(android.R.id.title))
|
|
||||||
.setText(userName.toString());
|
|
||||||
mUserManager.setUserName(mUser.getIdentifier(),
|
|
||||||
userName.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update the photo if changed.
|
|
||||||
Drawable drawable = mEditUserPhotoController.getNewUserPhotoDrawable();
|
|
||||||
Bitmap bitmap = mEditUserPhotoController.getNewUserPhotoBitmap();
|
|
||||||
if (drawable != null && bitmap != null
|
|
||||||
&& !drawable.equals(mUserIconView.getDrawable())) {
|
|
||||||
mUserIconView.setImageDrawable(drawable);
|
|
||||||
new AsyncTask<Void, Void, Void>() {
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... params) {
|
|
||||||
mUserManager.setUserIcon(mUser.getIdentifier(),
|
|
||||||
mEditUserPhotoController.getNewUserPhotoBitmap());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
|
|
||||||
}
|
|
||||||
removeDialog(DIALOG_ID_EDIT_USER_INFO);
|
|
||||||
}
|
|
||||||
clearEditUserInfoDialog();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
clearEditUserInfoDialog();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.create();
|
|
||||||
|
|
||||||
// Make sure the IME is up.
|
|
||||||
mEditUserInfoDialog.getWindow().setSoftInputMode(
|
|
||||||
WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
|
||||||
|
|
||||||
return mEditUserInfoDialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearEditUserInfoDialog() {
|
|
||||||
mEditUserInfoDialog = null;
|
|
||||||
mSavedPhoto = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class 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
|
|
||||||
// collide with ours, these values are very unlikely to have a conflict.
|
|
||||||
private static final int REQUEST_CODE_CHOOSE_PHOTO = Integer.MAX_VALUE;
|
|
||||||
private static final int REQUEST_CODE_TAKE_PHOTO = Integer.MAX_VALUE - 1;
|
|
||||||
private static final int REQUEST_CODE_CROP_PHOTO = Integer.MAX_VALUE - 2;
|
|
||||||
|
|
||||||
private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg";
|
|
||||||
private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto2.jpg";
|
|
||||||
|
|
||||||
private final int mPhotoSize;
|
|
||||||
|
|
||||||
private final Context mContext;
|
|
||||||
private final Fragment mFragment;
|
|
||||||
private final ImageView mImageView;
|
|
||||||
|
|
||||||
private final Uri mCropPictureUri;
|
|
||||||
private final Uri mTakePictureUri;
|
|
||||||
|
|
||||||
private Bitmap mNewUserPhotoBitmap;
|
|
||||||
private Drawable mNewUserPhotoDrawable;
|
|
||||||
|
|
||||||
public EditUserPhotoController(Fragment fragment, ImageView view,
|
|
||||||
Bitmap bitmap, Drawable drawable) {
|
|
||||||
mContext = view.getContext();
|
|
||||||
mFragment = fragment;
|
|
||||||
mImageView = view;
|
|
||||||
mCropPictureUri = createTempImageUri(mContext, CROP_PICTURE_FILE_NAME);
|
|
||||||
mTakePictureUri = createTempImageUri(mContext, TAKE_PICTURE_FILE_NAME);
|
|
||||||
mPhotoSize = getPhotoSize(mContext);
|
|
||||||
mImageView.setOnClickListener(new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
showUpdatePhotoPopup();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mNewUserPhotoBitmap = bitmap;
|
|
||||||
mNewUserPhotoDrawable = drawable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onActivityResult(int requestCode, int resultCode, final Intent data) {
|
|
||||||
if (resultCode != Activity.RESULT_OK) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
switch (requestCode) {
|
|
||||||
case REQUEST_CODE_CHOOSE_PHOTO:
|
|
||||||
case REQUEST_CODE_CROP_PHOTO: {
|
|
||||||
new AsyncTask<Void, Void, Bitmap>() {
|
|
||||||
@Override
|
|
||||||
protected Bitmap doInBackground(Void... params) {
|
|
||||||
return BitmapFactory.decodeFile(mCropPictureUri.getPath());
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Bitmap bitmap) {
|
|
||||||
mNewUserPhotoBitmap = bitmap;
|
|
||||||
mNewUserPhotoDrawable = CircleFramedDrawable
|
|
||||||
.getInstance(mImageView.getContext(), mNewUserPhotoBitmap);
|
|
||||||
mImageView.setImageDrawable(mNewUserPhotoDrawable);
|
|
||||||
// Delete the files - not needed anymore.
|
|
||||||
new File(mCropPictureUri.getPath()).delete();
|
|
||||||
new File(mTakePictureUri.getPath()).delete();
|
|
||||||
}
|
|
||||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
|
|
||||||
} return true;
|
|
||||||
case REQUEST_CODE_TAKE_PHOTO: {
|
|
||||||
cropPhoto();
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bitmap getNewUserPhotoBitmap() {
|
|
||||||
return mNewUserPhotoBitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Drawable getNewUserPhotoDrawable() {
|
|
||||||
return mNewUserPhotoDrawable;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showUpdatePhotoPopup() {
|
|
||||||
final boolean canTakePhoto = canTakePhoto();
|
|
||||||
final boolean canChoosePhoto = canChoosePhoto();
|
|
||||||
|
|
||||||
if (!canTakePhoto && !canChoosePhoto) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Context context = mImageView.getContext();
|
|
||||||
final List<AdapterItem> items = new ArrayList<AdapterItem>();
|
|
||||||
|
|
||||||
if (canTakePhoto()) {
|
|
||||||
String title = mImageView.getContext().getString( R.string.user_image_take_photo);
|
|
||||||
AdapterItem item = new AdapterItem(title, POPUP_LIST_ITEM_ID_TAKE_PHOTO);
|
|
||||||
items.add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canChoosePhoto) {
|
|
||||||
String title = context.getString(R.string.user_image_choose_photo);
|
|
||||||
AdapterItem item = new AdapterItem(title, POPUP_LIST_ITEM_ID_CHOOSE_PHOTO);
|
|
||||||
items.add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
final ListPopupWindow listPopupWindow = new ListPopupWindow(context);
|
|
||||||
|
|
||||||
listPopupWindow.setAnchorView(mImageView);
|
|
||||||
listPopupWindow.setModal(true);
|
|
||||||
listPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
|
|
||||||
|
|
||||||
ListAdapter adapter = new ArrayAdapter<AdapterItem>(context,
|
|
||||||
R.layout.edit_user_photo_popup_item, items);
|
|
||||||
listPopupWindow.setAdapter(adapter);
|
|
||||||
|
|
||||||
final int width = Math.max(mImageView.getWidth(), context.getResources()
|
|
||||||
.getDimensionPixelSize(R.dimen.update_user_photo_popup_min_width));
|
|
||||||
listPopupWindow.setWidth(width);
|
|
||||||
|
|
||||||
listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
|
||||||
AdapterItem item = items.get(position);
|
|
||||||
switch (item.id) {
|
|
||||||
case POPUP_LIST_ITEM_ID_CHOOSE_PHOTO: {
|
|
||||||
choosePhoto();
|
|
||||||
listPopupWindow.dismiss();
|
|
||||||
} break;
|
|
||||||
case POPUP_LIST_ITEM_ID_TAKE_PHOTO: {
|
|
||||||
takePhoto();
|
|
||||||
listPopupWindow.dismiss();
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
listPopupWindow.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean canTakePhoto() {
|
|
||||||
return mImageView.getContext().getPackageManager().queryIntentActivities(
|
|
||||||
new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
|
|
||||||
PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean canChoosePhoto() {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
|
||||||
intent.setType("image/*");
|
|
||||||
return mImageView.getContext().getPackageManager().queryIntentActivities(
|
|
||||||
intent, 0).size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void takePhoto() {
|
|
||||||
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
|
||||||
intent.putExtra(MediaStore.EXTRA_OUTPUT, mTakePictureUri);
|
|
||||||
mFragment.startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void choosePhoto() {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
|
|
||||||
intent.setType("image/*");
|
|
||||||
intent.putExtra(MediaStore.EXTRA_OUTPUT, mCropPictureUri);
|
|
||||||
appendCropExtras(intent);
|
|
||||||
mFragment.startActivityForResult(intent, REQUEST_CODE_CHOOSE_PHOTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cropPhoto() {
|
|
||||||
Intent intent = new Intent("com.android.camera.action.CROP");
|
|
||||||
intent.setDataAndType(mTakePictureUri, "image/*");
|
|
||||||
intent.putExtra(MediaStore.EXTRA_OUTPUT, mCropPictureUri);
|
|
||||||
appendCropExtras(intent);
|
|
||||||
mFragment.startActivityForResult(intent, REQUEST_CODE_CROP_PHOTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void appendCropExtras(Intent intent) {
|
|
||||||
intent.putExtra("crop", "true");
|
|
||||||
intent.putExtra("scale", true);
|
|
||||||
intent.putExtra("scaleUpIfNeeded", true);
|
|
||||||
intent.putExtra("aspectX", 1);
|
|
||||||
intent.putExtra("aspectY", 1);
|
|
||||||
intent.putExtra("outputX", mPhotoSize);
|
|
||||||
intent.putExtra("outputY", mPhotoSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getPhotoSize(Context context) {
|
|
||||||
Cursor cursor = context.getContentResolver().query(
|
|
||||||
DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
|
|
||||||
new String[]{DisplayPhoto.DISPLAY_MAX_DIM}, null, null, null);
|
|
||||||
try {
|
|
||||||
cursor.moveToFirst();
|
|
||||||
return cursor.getInt(0);
|
|
||||||
} finally {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Uri createTempImageUri(Context context, String fileName) {
|
|
||||||
File folder = context.getExternalCacheDir();
|
|
||||||
folder.mkdirs();
|
|
||||||
File fullPath = new File(folder, fileName);
|
|
||||||
fullPath.delete();
|
|
||||||
return Uri.fromFile(fullPath.getAbsoluteFile());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class AdapterItem {
|
|
||||||
final String title;
|
|
||||||
final int id;
|
|
||||||
|
|
||||||
public AdapterItem(String title, int id) {
|
|
||||||
this.title = title;
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
449
src/com/android/settings/users/RestrictedProfileSettings.java
Normal file
449
src/com/android/settings/users/RestrictedProfileSettings.java
Normal file
@@ -0,0 +1,449 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.users;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.Fragment;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
import android.provider.ContactsContract.DisplayPhoto;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ListAdapter;
|
||||||
|
import android.widget.ListPopupWindow;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class RestrictedProfileSettings extends AppRestrictionsFragment {
|
||||||
|
|
||||||
|
private static final String KEY_SAVED_PHOTO = "pending_photo";
|
||||||
|
private static final int DIALOG_ID_EDIT_USER_INFO = 1;
|
||||||
|
|
||||||
|
private View mHeaderView;
|
||||||
|
private ImageView mUserIconView;
|
||||||
|
private TextView mUserNameView;
|
||||||
|
|
||||||
|
private Dialog mEditUserInfoDialog;
|
||||||
|
private EditUserPhotoController mEditUserPhotoController;
|
||||||
|
private Bitmap mSavedPhoto;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle icicle) {
|
||||||
|
super.onCreate(icicle);
|
||||||
|
|
||||||
|
if (icicle != null) {
|
||||||
|
mSavedPhoto = (Bitmap) icicle.getParcelable(KEY_SAVED_PHOTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
init(icicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
|
if (mHeaderView == null) {
|
||||||
|
mHeaderView = LayoutInflater.from(getActivity()).inflate(
|
||||||
|
R.layout.user_info_header, null);
|
||||||
|
((ViewGroup) getListView().getParent()).addView(mHeaderView, 0);
|
||||||
|
mHeaderView.setOnClickListener(this);
|
||||||
|
mUserIconView = (ImageView) mHeaderView.findViewById(android.R.id.icon);
|
||||||
|
mUserNameView = (TextView) mHeaderView.findViewById(android.R.id.title);
|
||||||
|
getListView().setFastScrollEnabled(true);
|
||||||
|
}
|
||||||
|
// This is going to bind the preferences.
|
||||||
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
if (mEditUserInfoDialog != null && mEditUserInfoDialog.isShowing()
|
||||||
|
&& mEditUserPhotoController != null) {
|
||||||
|
outState.putParcelable(KEY_SAVED_PHOTO,
|
||||||
|
mEditUserPhotoController.getNewUserPhotoBitmap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
UserInfo info = mUserManager.getUserInfo(mUser.getIdentifier());
|
||||||
|
((TextView) mHeaderView.findViewById(android.R.id.title)).setText(info.name);
|
||||||
|
((ImageView) mHeaderView.findViewById(android.R.id.icon)).setImageDrawable(
|
||||||
|
getCircularUserIcon());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
if (mEditUserInfoDialog != null && mEditUserInfoDialog.isShowing()
|
||||||
|
&& mEditUserPhotoController.onActivityResult(requestCode, resultCode, data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
if (view == mHeaderView) {
|
||||||
|
showDialog(DIALOG_ID_EDIT_USER_INFO);
|
||||||
|
} else {
|
||||||
|
super.onClick(view); // in AppRestrictionsFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(int dialogId) {
|
||||||
|
if (dialogId == DIALOG_ID_EDIT_USER_INFO) {
|
||||||
|
if (mEditUserInfoDialog != null) {
|
||||||
|
return mEditUserInfoDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||||
|
View content = inflater.inflate(R.layout.edit_user_info_dialog_content, null);
|
||||||
|
|
||||||
|
UserInfo info = mUserManager.getUserInfo(mUser.getIdentifier());
|
||||||
|
|
||||||
|
final EditText userNameView = (EditText) content.findViewById(R.id.user_name);
|
||||||
|
userNameView.setText(info.name);
|
||||||
|
|
||||||
|
final ImageView userPhotoView = (ImageView) content.findViewById(R.id.user_photo);
|
||||||
|
Drawable drawable = null;
|
||||||
|
if (mSavedPhoto != null) {
|
||||||
|
drawable = CircleFramedDrawable.getInstance(getActivity(), mSavedPhoto);
|
||||||
|
} else {
|
||||||
|
drawable = mUserIconView.getDrawable();
|
||||||
|
if (drawable == null) {
|
||||||
|
drawable = getCircularUserIcon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userPhotoView.setImageDrawable(drawable);
|
||||||
|
|
||||||
|
mEditUserPhotoController = new EditUserPhotoController(this, userPhotoView,
|
||||||
|
mSavedPhoto, drawable);
|
||||||
|
|
||||||
|
mEditUserInfoDialog = new AlertDialog.Builder(getActivity())
|
||||||
|
.setTitle(R.string.profile_info_settings_title)
|
||||||
|
.setIconAttribute(R.drawable.ic_settings_multiuser)
|
||||||
|
.setView(content)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||||
|
// Update the name if changed.
|
||||||
|
CharSequence userName = userNameView.getText();
|
||||||
|
if (!TextUtils.isEmpty(userName)) {
|
||||||
|
CharSequence oldUserName = mUserNameView.getText();
|
||||||
|
if (oldUserName == null
|
||||||
|
|| !userName.toString().equals(oldUserName.toString())) {
|
||||||
|
((TextView) mHeaderView.findViewById(android.R.id.title))
|
||||||
|
.setText(userName.toString());
|
||||||
|
mUserManager.setUserName(mUser.getIdentifier(),
|
||||||
|
userName.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update the photo if changed.
|
||||||
|
Drawable drawable = mEditUserPhotoController.getNewUserPhotoDrawable();
|
||||||
|
Bitmap bitmap = mEditUserPhotoController.getNewUserPhotoBitmap();
|
||||||
|
if (drawable != null && bitmap != null
|
||||||
|
&& !drawable.equals(mUserIconView.getDrawable())) {
|
||||||
|
mUserIconView.setImageDrawable(drawable);
|
||||||
|
new AsyncTask<Void, Void, Void>() {
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... params) {
|
||||||
|
mUserManager.setUserIcon(mUser.getIdentifier(),
|
||||||
|
mEditUserPhotoController.getNewUserPhotoBitmap());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
|
||||||
|
}
|
||||||
|
removeDialog(DIALOG_ID_EDIT_USER_INFO);
|
||||||
|
}
|
||||||
|
clearEditUserInfoDialog();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
clearEditUserInfoDialog();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create();
|
||||||
|
|
||||||
|
// Make sure the IME is up.
|
||||||
|
mEditUserInfoDialog.getWindow().setSoftInputMode(
|
||||||
|
WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
||||||
|
|
||||||
|
return mEditUserInfoDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearEditUserInfoDialog() {
|
||||||
|
mEditUserInfoDialog = null;
|
||||||
|
mSavedPhoto = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class 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
|
||||||
|
// collide with ours, these values are very unlikely to have a conflict.
|
||||||
|
private static final int REQUEST_CODE_CHOOSE_PHOTO = 1;
|
||||||
|
private static final int REQUEST_CODE_TAKE_PHOTO = 2;
|
||||||
|
private static final int REQUEST_CODE_CROP_PHOTO = 3;
|
||||||
|
|
||||||
|
private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg";
|
||||||
|
private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto2.jpg";
|
||||||
|
|
||||||
|
private final int mPhotoSize;
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final Fragment mFragment;
|
||||||
|
private final ImageView mImageView;
|
||||||
|
|
||||||
|
private final Uri mCropPictureUri;
|
||||||
|
private final Uri mTakePictureUri;
|
||||||
|
|
||||||
|
private Bitmap mNewUserPhotoBitmap;
|
||||||
|
private Drawable mNewUserPhotoDrawable;
|
||||||
|
|
||||||
|
public EditUserPhotoController(Fragment fragment, ImageView view,
|
||||||
|
Bitmap bitmap, Drawable drawable) {
|
||||||
|
mContext = view.getContext();
|
||||||
|
mFragment = fragment;
|
||||||
|
mImageView = view;
|
||||||
|
mCropPictureUri = createTempImageUri(mContext, CROP_PICTURE_FILE_NAME);
|
||||||
|
mTakePictureUri = createTempImageUri(mContext, TAKE_PICTURE_FILE_NAME);
|
||||||
|
mPhotoSize = getPhotoSize(mContext);
|
||||||
|
mImageView.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
showUpdatePhotoPopup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mNewUserPhotoBitmap = bitmap;
|
||||||
|
mNewUserPhotoDrawable = drawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onActivityResult(int requestCode, int resultCode, final Intent data) {
|
||||||
|
if (resultCode != Activity.RESULT_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (requestCode) {
|
||||||
|
case REQUEST_CODE_CHOOSE_PHOTO:
|
||||||
|
case REQUEST_CODE_CROP_PHOTO: {
|
||||||
|
new AsyncTask<Void, Void, Bitmap>() {
|
||||||
|
@Override
|
||||||
|
protected Bitmap doInBackground(Void... params) {
|
||||||
|
return BitmapFactory.decodeFile(mCropPictureUri.getPath());
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Bitmap bitmap) {
|
||||||
|
mNewUserPhotoBitmap = bitmap;
|
||||||
|
mNewUserPhotoDrawable = CircleFramedDrawable
|
||||||
|
.getInstance(mImageView.getContext(), mNewUserPhotoBitmap);
|
||||||
|
mImageView.setImageDrawable(mNewUserPhotoDrawable);
|
||||||
|
// Delete the files - not needed anymore.
|
||||||
|
new File(mCropPictureUri.getPath()).delete();
|
||||||
|
new File(mTakePictureUri.getPath()).delete();
|
||||||
|
}
|
||||||
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
|
||||||
|
} return true;
|
||||||
|
case REQUEST_CODE_TAKE_PHOTO: {
|
||||||
|
cropPhoto();
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap getNewUserPhotoBitmap() {
|
||||||
|
return mNewUserPhotoBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable getNewUserPhotoDrawable() {
|
||||||
|
return mNewUserPhotoDrawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showUpdatePhotoPopup() {
|
||||||
|
final boolean canTakePhoto = canTakePhoto();
|
||||||
|
final boolean canChoosePhoto = canChoosePhoto();
|
||||||
|
|
||||||
|
if (!canTakePhoto && !canChoosePhoto) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Context context = mImageView.getContext();
|
||||||
|
final List<AdapterItem> items = new ArrayList<AdapterItem>();
|
||||||
|
|
||||||
|
if (canTakePhoto()) {
|
||||||
|
String title = mImageView.getContext().getString( R.string.user_image_take_photo);
|
||||||
|
AdapterItem item = new AdapterItem(title, POPUP_LIST_ITEM_ID_TAKE_PHOTO);
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canChoosePhoto) {
|
||||||
|
String title = context.getString(R.string.user_image_choose_photo);
|
||||||
|
AdapterItem item = new AdapterItem(title, POPUP_LIST_ITEM_ID_CHOOSE_PHOTO);
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListPopupWindow listPopupWindow = new ListPopupWindow(context);
|
||||||
|
|
||||||
|
listPopupWindow.setAnchorView(mImageView);
|
||||||
|
listPopupWindow.setModal(true);
|
||||||
|
listPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
|
||||||
|
|
||||||
|
ListAdapter adapter = new ArrayAdapter<AdapterItem>(context,
|
||||||
|
R.layout.edit_user_photo_popup_item, items);
|
||||||
|
listPopupWindow.setAdapter(adapter);
|
||||||
|
|
||||||
|
final int width = Math.max(mImageView.getWidth(), context.getResources()
|
||||||
|
.getDimensionPixelSize(R.dimen.update_user_photo_popup_min_width));
|
||||||
|
listPopupWindow.setWidth(width);
|
||||||
|
|
||||||
|
listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
AdapterItem item = items.get(position);
|
||||||
|
switch (item.id) {
|
||||||
|
case POPUP_LIST_ITEM_ID_CHOOSE_PHOTO: {
|
||||||
|
choosePhoto();
|
||||||
|
listPopupWindow.dismiss();
|
||||||
|
} break;
|
||||||
|
case POPUP_LIST_ITEM_ID_TAKE_PHOTO: {
|
||||||
|
takePhoto();
|
||||||
|
listPopupWindow.dismiss();
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
listPopupWindow.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canTakePhoto() {
|
||||||
|
return mImageView.getContext().getPackageManager().queryIntentActivities(
|
||||||
|
new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
|
||||||
|
PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canChoosePhoto() {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
|
intent.setType("image/*");
|
||||||
|
return mImageView.getContext().getPackageManager().queryIntentActivities(
|
||||||
|
intent, 0).size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void takePhoto() {
|
||||||
|
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||||
|
intent.putExtra(MediaStore.EXTRA_OUTPUT, mTakePictureUri);
|
||||||
|
mFragment.startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void choosePhoto() {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
|
||||||
|
intent.setType("image/*");
|
||||||
|
intent.putExtra(MediaStore.EXTRA_OUTPUT, mCropPictureUri);
|
||||||
|
appendCropExtras(intent);
|
||||||
|
mFragment.startActivityForResult(intent, REQUEST_CODE_CHOOSE_PHOTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cropPhoto() {
|
||||||
|
Intent intent = new Intent("com.android.camera.action.CROP");
|
||||||
|
intent.setDataAndType(mTakePictureUri, "image/*");
|
||||||
|
intent.putExtra(MediaStore.EXTRA_OUTPUT, mCropPictureUri);
|
||||||
|
appendCropExtras(intent);
|
||||||
|
mFragment.startActivityForResult(intent, REQUEST_CODE_CROP_PHOTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendCropExtras(Intent intent) {
|
||||||
|
intent.putExtra("crop", "true");
|
||||||
|
intent.putExtra("scale", true);
|
||||||
|
intent.putExtra("scaleUpIfNeeded", true);
|
||||||
|
intent.putExtra("aspectX", 1);
|
||||||
|
intent.putExtra("aspectY", 1);
|
||||||
|
intent.putExtra("outputX", mPhotoSize);
|
||||||
|
intent.putExtra("outputY", mPhotoSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getPhotoSize(Context context) {
|
||||||
|
Cursor cursor = context.getContentResolver().query(
|
||||||
|
DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
|
||||||
|
new String[]{DisplayPhoto.DISPLAY_MAX_DIM}, null, null, null);
|
||||||
|
try {
|
||||||
|
cursor.moveToFirst();
|
||||||
|
return cursor.getInt(0);
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri createTempImageUri(Context context, String fileName) {
|
||||||
|
File folder = context.getExternalCacheDir();
|
||||||
|
folder.mkdirs();
|
||||||
|
File fullPath = new File(folder, fileName);
|
||||||
|
fullPath.delete();
|
||||||
|
return Uri.fromFile(fullPath.getAbsoluteFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class AdapterItem {
|
||||||
|
final String title;
|
||||||
|
final int id;
|
||||||
|
|
||||||
|
public AdapterItem(String title, int id) {
|
||||||
|
this.title = title;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
147
src/com/android/settings/users/RestrictionSettings.java
Normal file
147
src/com/android/settings/users/RestrictionSettings.java
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.users;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for restricting regular users, including single-user devices.
|
||||||
|
*/
|
||||||
|
public class RestrictionSettings extends AppRestrictionsFragment {
|
||||||
|
|
||||||
|
private static final int REQUEST_PIN_CHALLENGE = 10;
|
||||||
|
|
||||||
|
private static final int MENU_RESET = Menu.FIRST + 1;
|
||||||
|
private static final int MENU_CHANGE_PIN = Menu.FIRST + 2;
|
||||||
|
|
||||||
|
private static final String KEY_CHALLENGE_REQUESTED = "chrq";
|
||||||
|
|
||||||
|
private boolean mChallengeSucceeded;
|
||||||
|
private boolean mChallengeRequested;
|
||||||
|
|
||||||
|
public void onCreate(Bundle icicle) {
|
||||||
|
super.onCreate(icicle);
|
||||||
|
|
||||||
|
init(icicle);
|
||||||
|
mChallengeSucceeded = false;
|
||||||
|
mChallengeRequested = icicle != null
|
||||||
|
? icicle.getBoolean(KEY_CHALLENGE_REQUESTED, false)
|
||||||
|
: false;
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
if (!mChallengeSucceeded) {
|
||||||
|
getListView().setEnabled(false);
|
||||||
|
final UserManager um = UserManager.get(getActivity());
|
||||||
|
if (!mChallengeRequested) {
|
||||||
|
if (um.hasRestrictionsPin()) {
|
||||||
|
Intent requestPin =
|
||||||
|
new Intent(Intent.ACTION_RESTRICTIONS_PIN_CHALLENGE);
|
||||||
|
startActivityForResult(requestPin, REQUEST_PIN_CHALLENGE);
|
||||||
|
} else {
|
||||||
|
Intent requestPin =
|
||||||
|
new Intent("android.intent.action.RESTRICTIONS_PIN_CREATE");
|
||||||
|
startActivityForResult(requestPin, REQUEST_PIN_CHALLENGE);
|
||||||
|
}
|
||||||
|
mChallengeRequested = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mChallengeSucceeded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetAndRemovePin() {
|
||||||
|
final UserManager um = UserManager.get(getActivity());
|
||||||
|
final PackageManager pm = getActivity().getPackageManager();
|
||||||
|
List<ApplicationInfo> installedApps = pm.getInstalledApplications(
|
||||||
|
PackageManager.GET_UNINSTALLED_PACKAGES);
|
||||||
|
UserHandle user = android.os.Process.myUserHandle();
|
||||||
|
for (ApplicationInfo info: installedApps) {
|
||||||
|
if ((info.flags & ApplicationInfo.FLAG_BLOCKED) != 0
|
||||||
|
&& (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
|
||||||
|
pm.setApplicationBlockedSettingAsUser(info.packageName, false, user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
um.changeRestrictionsPin(null);
|
||||||
|
clearSelectedApps();
|
||||||
|
finishFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changePin() {
|
||||||
|
final UserManager um = UserManager.get(getActivity());
|
||||||
|
um.changeRestrictionsPin(null);
|
||||||
|
Intent requestPin = new Intent("android.intent.action.RESTRICTIONS_PIN_CREATE");
|
||||||
|
startActivityForResult(requestPin, REQUEST_PIN_CHALLENGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (requestCode == REQUEST_PIN_CHALLENGE) {
|
||||||
|
mChallengeRequested = false;
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
getListView().setEnabled(true);
|
||||||
|
mChallengeSucceeded = true;
|
||||||
|
} else {
|
||||||
|
finishFragment();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putBoolean(KEY_CHALLENGE_REQUESTED, mChallengeRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
menu.add(0, MENU_RESET, 0, R.string.restriction_menu_reset);
|
||||||
|
menu.add(0, MENU_CHANGE_PIN, 0, R.string.restriction_menu_change_pin);
|
||||||
|
|
||||||
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case MENU_RESET:
|
||||||
|
resetAndRemovePin();
|
||||||
|
return true;
|
||||||
|
case MENU_CHANGE_PIN:
|
||||||
|
changePin();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
@@ -134,7 +134,6 @@ public class UserSettings extends SettingsPreferenceFragment
|
|||||||
private final Object mUserLock = new Object();
|
private final Object mUserLock = new Object();
|
||||||
private UserManager mUserManager;
|
private UserManager mUserManager;
|
||||||
private SparseArray<Bitmap> mUserIcons = new SparseArray<Bitmap>();
|
private SparseArray<Bitmap> mUserIcons = new SparseArray<Bitmap>();
|
||||||
private Drawable mDefaultCircleAvatar;
|
|
||||||
private boolean mIsOwner = UserHandle.myUserId() == UserHandle.USER_OWNER;
|
private boolean mIsOwner = UserHandle.myUserId() == UserHandle.USER_OWNER;
|
||||||
|
|
||||||
|
|
||||||
@@ -201,10 +200,15 @@ public class UserSettings extends SettingsPreferenceFragment
|
|||||||
loadProfile();
|
loadProfile();
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
|
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
|
||||||
filter.addAction(Intent.ACTION_USER_ADDED);
|
|
||||||
filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
|
filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
|
||||||
getActivity().registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null,
|
getActivity().registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null,
|
||||||
mHandler);
|
mHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
loadProfile();
|
||||||
updateUserList();
|
updateUserList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,13 +283,6 @@ public class UserSettings extends SettingsPreferenceFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable getDefaultCircleAvatar() {
|
|
||||||
if (mDefaultCircleAvatar == null) {
|
|
||||||
mDefaultCircleAvatar = encircle(R.drawable.avatar_default_1);
|
|
||||||
}
|
|
||||||
return mDefaultCircleAvatar;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasLockscreenSecurity() {
|
private boolean hasLockscreenSecurity() {
|
||||||
LockPatternUtils lpu = new LockPatternUtils(getActivity());
|
LockPatternUtils lpu = new LockPatternUtils(getActivity());
|
||||||
return lpu.isLockPasswordEnabled() || lpu.isLockPatternEnabled();
|
return lpu.isLockPasswordEnabled() || lpu.isLockPatternEnabled();
|
||||||
@@ -377,10 +374,10 @@ public class UserSettings extends SettingsPreferenceFragment
|
|||||||
UserInfo info = mUserManager.getUserInfo(userId);
|
UserInfo info = mUserManager.getUserInfo(userId);
|
||||||
if (info.isRestricted() && mIsOwner) {
|
if (info.isRestricted() && mIsOwner) {
|
||||||
Bundle extras = new Bundle();
|
Bundle extras = new Bundle();
|
||||||
extras.putInt(AppRestrictionsFragment.EXTRA_USER_ID, userId);
|
extras.putInt(RestrictedProfileSettings.EXTRA_USER_ID, userId);
|
||||||
extras.putBoolean(AppRestrictionsFragment.EXTRA_NEW_USER, newUser);
|
extras.putBoolean(RestrictedProfileSettings.EXTRA_NEW_USER, newUser);
|
||||||
((PreferenceActivity) getActivity()).startPreferencePanel(
|
((PreferenceActivity) getActivity()).startPreferencePanel(
|
||||||
AppRestrictionsFragment.class.getName(),
|
RestrictedProfileSettings.class.getName(),
|
||||||
extras, R.string.user_restrictions_title, null,
|
extras, R.string.user_restrictions_title, null,
|
||||||
null, 0);
|
null, 0);
|
||||||
} else if (info.id == UserHandle.myUserId()) {
|
} else if (info.id == UserHandle.myUserId()) {
|
||||||
@@ -641,7 +638,7 @@ public class UserSettings extends SettingsPreferenceFragment
|
|||||||
if (user.iconPath != null) {
|
if (user.iconPath != null) {
|
||||||
if (mUserIcons.get(user.id) == null) {
|
if (mUserIcons.get(user.id) == null) {
|
||||||
missingIcons.add(user.id);
|
missingIcons.add(user.id);
|
||||||
pref.setIcon(getDefaultCircleAvatar());
|
pref.setIcon(encircle(R.drawable.avatar_default_1));
|
||||||
} else {
|
} else {
|
||||||
setPhotoId(pref, user);
|
setPhotoId(pref, user);
|
||||||
}
|
}
|
||||||
@@ -653,7 +650,7 @@ public class UserSettings extends SettingsPreferenceFragment
|
|||||||
null, null);
|
null, null);
|
||||||
pref.setEnabled(false);
|
pref.setEnabled(false);
|
||||||
pref.setTitle(R.string.user_new_user_name);
|
pref.setTitle(R.string.user_new_user_name);
|
||||||
pref.setIcon(getDefaultCircleAvatar());
|
pref.setIcon(encircle(R.drawable.avatar_default_1));
|
||||||
mUserListCategory.addPreference(pref);
|
mUserListCategory.addPreference(pref);
|
||||||
}
|
}
|
||||||
getActivity().invalidateOptionsMenu();
|
getActivity().invalidateOptionsMenu();
|
||||||
|
Reference in New Issue
Block a user