From 2ebc8a01696c4e7dd29863b92a15ae0bbbbb254d Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Fri, 13 Feb 2015 15:23:19 -0500 Subject: [PATCH] Allow system apps to add to settings dashboard Allow system apps to add a tile to the top level of settings that links to an activity through adding a filter for a specific action. Determine the info for the tile based off manifest info for the activity. Also allow the same for managed profiles, but show a dialog in between to select which profile. The category in which the item is to be placed must be in meta-data. The icon and title can be specified through meta-data as well or if unspecified the activity's label and icon will be used. Also added an optional tag to the dashboard category xml, this allows Settings to put external tiles in the middle of some categories (Personal does this). Bug: 19443117 Change-Id: Idc9938d1549d181103a3030a8784b527215a8399 --- res/layout/user_preference.xml | 4 +- res/values/dimens.xml | 1 + res/values/donottranslate.xml | 4 + res/values/strings.xml | 3 + res/xml/dashboard_categories.xml | 7 + .../android/settings/ProfileSelectDialog.java | 68 ++++++++++ .../android/settings/SettingsActivity.java | 123 +++++++++++++++++- ...erSpinnerAdapter.java => UserAdapter.java} | 28 +++- src/com/android/settings/Utils.java | 55 +++++--- .../settings/dashboard/DashboardCategory.java | 14 ++ .../settings/dashboard/DashboardSummary.java | 12 +- .../settings/dashboard/DashboardTile.java | 24 ++++ .../settings/dashboard/DashboardTileView.java | 13 +- .../settings/print/PrintSettingsFragment.java | 9 +- 14 files changed, 328 insertions(+), 37 deletions(-) create mode 100644 src/com/android/settings/ProfileSelectDialog.java rename src/com/android/settings/{UserSpinnerAdapter.java => UserAdapter.java} (86%) diff --git a/res/layout/user_preference.xml b/res/layout/user_preference.xml index 91db846cbc5..8e81fec4d32 100644 --- a/res/layout/user_preference.xml +++ b/res/layout/user_preference.xml @@ -18,6 +18,8 @@ android:id="@android:id/widget_frame" android:layout_width="match_parent" android:layout_height="@dimen/user_spinner_item_height" + android:paddingStart="@dimen/user_spinner_padding_sides" + android:paddingEnd="@dimen/user_spinner_padding_sides" android:orientation="horizontal" > - \ No newline at end of file + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 5ed69c45c84..580ae22d125 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -213,6 +213,7 @@ 72dp 4dp + 20dp 56dp diff --git a/res/values/donottranslate.xml b/res/values/donottranslate.xml index e6bd9a6bb7b..611e2b4b021 100644 --- a/res/values/donottranslate.xml +++ b/res/values/donottranslate.xml @@ -33,4 +33,8 @@ @string/input_method_selector_always_show_value @string/input_method_selector_always_hide_value + com.android.settings.category.wireless + com.android.settings.category.device + com.android.settings.category.personal + com.android.settings.category.system diff --git a/res/values/strings.xml b/res/values/strings.xml index 4c13e4a217f..c445f779651 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6132,4 +6132,7 @@ Unknown app + + Choose Profile + diff --git a/res/xml/dashboard_categories.xml b/res/xml/dashboard_categories.xml index 01a4f8386c1..0d8c1ac5873 100644 --- a/res/xml/dashboard_categories.xml +++ b/res/xml/dashboard_categories.xml @@ -20,6 +20,7 @@ @@ -74,6 +75,7 @@ @@ -152,6 +154,7 @@ @@ -178,6 +181,9 @@ android:icon="@drawable/ic_settings_accounts" /> + + + diff --git a/src/com/android/settings/ProfileSelectDialog.java b/src/com/android/settings/ProfileSelectDialog.java new file mode 100644 index 00000000000..99f962fdcf7 --- /dev/null +++ b/src/com/android/settings/ProfileSelectDialog.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 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; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.app.FragmentManager; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; + +import com.android.settings.dashboard.DashboardTile; + +public class ProfileSelectDialog extends DialogFragment implements OnClickListener { + + private static final String ARG_SELECTED_TILE = "selectedTile"; + + private DashboardTile mSelectedTile; + + public static void show(FragmentManager manager, DashboardTile tile) { + ProfileSelectDialog dialog = new ProfileSelectDialog(); + Bundle args = new Bundle(); + args.putParcelable(ARG_SELECTED_TILE, tile); + dialog.setArguments(args); + dialog.show(manager, "select_profile"); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mSelectedTile = getArguments().getParcelable(ARG_SELECTED_TILE); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Context context = getActivity(); + AlertDialog.Builder builder = new AlertDialog.Builder(context); + UserAdapter adapter = Utils.createUserAdapter(UserManager.get(context), context, + mSelectedTile.userHandle); + builder.setTitle(R.string.choose_profile) + .setAdapter(adapter, this); + + return builder.create(); + } + + @Override + public void onClick(DialogInterface dialog, int which) { + UserHandle user = mSelectedTile.userHandle.get(which); + getActivity().startActivityAsUser(mSelectedTile.intent, user); + } +} diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 0f0c89775a4..eecf7a207b4 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -16,6 +16,8 @@ package com.android.settings; +import static com.android.settings.dashboard.DashboardTile.TILE_ID_UNDEFINED; + import android.app.ActionBar; import android.app.Activity; import android.app.Fragment; @@ -49,8 +51,10 @@ import android.preference.PreferenceManager; import android.preference.PreferenceScreen; import android.text.TextUtils; import android.transition.TransitionManager; +import android.util.ArrayMap; import android.util.AttributeSet; import android.util.Log; +import android.util.Pair; import android.util.TypedValue; import android.util.Xml; import android.view.Menu; @@ -81,9 +85,6 @@ import com.android.settings.deviceinfo.Memory; import com.android.settings.deviceinfo.UsbSettings; import com.android.settings.fuelgauge.BatterySaverSettings; import com.android.settings.fuelgauge.PowerUsageSummary; -import com.android.settings.notification.OtherSoundSettings; -import com.android.settings.search.DynamicIndexableContentMonitor; -import com.android.settings.search.Index; import com.android.settings.inputmethod.InputMethodAndLanguageSettings; import com.android.settings.inputmethod.KeyboardLayoutPickerFragment; import com.android.settings.inputmethod.SpellCheckersSettings; @@ -96,9 +97,12 @@ import com.android.settings.notification.ConditionProviderSettings; import com.android.settings.notification.NotificationAccessSettings; import com.android.settings.notification.NotificationSettings; import com.android.settings.notification.NotificationStation; +import com.android.settings.notification.OtherSoundSettings; import com.android.settings.notification.ZenModeSettings; import com.android.settings.print.PrintJobSettingsFragment; import com.android.settings.print.PrintSettingsFragment; +import com.android.settings.search.DynamicIndexableContentMonitor; +import com.android.settings.search.Index; import com.android.settings.sim.SimSettings; import com.android.settings.tts.TextToSpeechSettings; import com.android.settings.users.UserSettings; @@ -110,16 +114,16 @@ import com.android.settings.wifi.AdvancedWifiSettings; import com.android.settings.wifi.SavedAccessPointsWifiSettings; import com.android.settings.wifi.WifiSettings; import com.android.settings.wifi.p2p.WifiP2pSettings; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; -import static com.android.settings.dashboard.DashboardTile.TILE_ID_UNDEFINED; - public class SettingsActivity extends Activity implements PreferenceManager.OnPreferenceTreeClickListener, PreferenceFragment.OnPreferenceStartFragmentCallback, @@ -201,6 +205,35 @@ public class SettingsActivity extends Activity private static final String EMPTY_QUERY = ""; + /** + * Settings will search for system activities of this action and add them as a top level + * settings tile using the following parameters. + * + *

A category must be specified in the meta-data for the activity named + * {@link #EXTRA_CATEGORY_KEY} + * + *

The title may be defined by meta-data named {@link Utils#META_DATA_PREFERENCE_TITLE} + * otherwise the label for the activity will be used. + * + *

The icon may be defined by meta-data named {@link Utils#META_DATA_PREFERENCE_ICON} + * otherwise the icon for the activity will be used. + * + *

A summary my be defined by meta-data named {@link Utils#META_DATA_PREFERENCE_SUMMARY} + */ + private static final String EXTRA_SETTINGS_ACTION = + "com.android.settings.action.EXTRA_SETTINGS"; + + /** + * The key used to get the category from metadata of activities of action + * {@link #EXTRA_SETTINGS_ACTION} + * The value must be one of: + *

  • com.android.settings.category.wireless
  • + *
  • com.android.settings.category.device
  • + *
  • com.android.settings.category.personal
  • + *
  • com.android.settings.category.system
  • + */ + private static final String EXTRA_CATEGORY_KEY = "com.android.settings.category"; + private static boolean sShowNoHomeNotice = false; private String mFragmentClass; @@ -1035,6 +1068,17 @@ public class SettingsActivity extends Activity } } sa.recycle(); + sa = obtainStyledAttributes(attrs, com.android.internal.R.styleable.Preference); + tv = sa.peekValue( + com.android.internal.R.styleable.Preference_key); + if (tv != null && tv.type == TypedValue.TYPE_STRING) { + if (tv.resourceId != 0) { + category.key = getString(tv.resourceId); + } else { + category.key = tv.string.toString(); + } + } + sa.recycle(); final int innerDepth = parser.getDepth(); while ((type=parser.next()) != XmlPullParser.END_DOCUMENT @@ -1110,6 +1154,8 @@ public class SettingsActivity extends Activity category.addTile(tile); } + } else if (innerNodeName.equals("external-tiles")) { + category.externalIndex = category.getTilesCount(); } else { XmlUtils.skipCurrentTag(parser); } @@ -1231,6 +1277,73 @@ public class SettingsActivity extends Activity n--; } } + addExternalTiles(target); + } + + private void addExternalTiles(List target) { + Map, DashboardTile> addedCache = + new ArrayMap, DashboardTile>(); + UserManager userManager = UserManager.get(this); + for (UserHandle user : userManager.getUserProfiles()) { + addExternalTiles(target, user, addedCache); + } + } + + private void addExternalTiles(List target, UserHandle user, + Map, DashboardTile> addedCache) { + PackageManager pm = getPackageManager(); + Intent intent = new Intent(EXTRA_SETTINGS_ACTION); + List results = pm.queryIntentActivitiesAsUser(intent, + PackageManager.GET_META_DATA, user.getIdentifier()); + for (ResolveInfo resolved : results) { + if (!resolved.system) { + // Do not allow any app to add to settings, only system ones. + continue; + } + ActivityInfo activityInfo = resolved.activityInfo; + Bundle metaData = activityInfo.metaData; + if ((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY)) { + Log.w(LOG_TAG, "Found " + resolved.activityInfo.name + " for action " + + EXTRA_SETTINGS_ACTION + " missing metadata " + + (metaData == null ? "" : EXTRA_CATEGORY_KEY)); + continue; + } + String categoryKey = metaData.getString(EXTRA_CATEGORY_KEY); + DashboardCategory category = getCategory(target, categoryKey); + if (category == null) { + Log.w(LOG_TAG, "Activity " + resolved.activityInfo.name + " has unknown " + + "category key " + categoryKey); + continue; + } + Pair key = new Pair(activityInfo.packageName, + activityInfo.name); + DashboardTile tile = addedCache.get(key); + if (tile == null) { + tile = new DashboardTile(); + tile.intent = new Intent().setClassName( + activityInfo.packageName, activityInfo.name); + Utils.updateTileToSpecificActivityFromMetaDataOrRemove(this, tile); + + if (category.externalIndex == -1) { + // If no location for external tiles has been specified for this category, + // then just put them at the end. + category.addTile(tile); + } else { + category.addTile(category.externalIndex, tile); + } + addedCache.put(key, tile); + } + tile.userHandle.add(user); + } + } + + private DashboardCategory getCategory(List target, String categoryKey) { + for (DashboardCategory category : target) { + if (categoryKey.equals(category.key)) { + return category; + } + } + return null; } private boolean updateHomeSettingTiles(DashboardTile tile) { diff --git a/src/com/android/settings/UserSpinnerAdapter.java b/src/com/android/settings/UserAdapter.java similarity index 86% rename from src/com/android/settings/UserSpinnerAdapter.java rename to src/com/android/settings/UserAdapter.java index e40a374d5a7..dcdc7eb0d2d 100644 --- a/src/com/android/settings/UserSpinnerAdapter.java +++ b/src/com/android/settings/UserAdapter.java @@ -16,6 +16,7 @@ package com.android.settings; +import android.app.ActivityManager; import android.content.Context; import android.content.pm.UserInfo; import android.database.DataSetObserver; @@ -27,6 +28,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; +import android.widget.ListAdapter; import android.widget.SpinnerAdapter; import android.widget.TextView; @@ -38,7 +40,7 @@ import java.util.ArrayList; /** * Adapter for a spinner that shows a list of users. */ -public class UserSpinnerAdapter implements SpinnerAdapter { +public class UserAdapter implements SpinnerAdapter, ListAdapter { // TODO: Update UI. See: http://b/16518801 /** Holder for user details */ public static class UserDetails { @@ -73,7 +75,7 @@ public class UserSpinnerAdapter implements SpinnerAdapter { private ArrayList data; private final LayoutInflater mInflater; - public UserSpinnerAdapter(Context context, ArrayList users) { + public UserAdapter(Context context, ArrayList users) { if (users == null) { throw new IllegalArgumentException("A list of user details must be provided"); } @@ -94,10 +96,20 @@ public class UserSpinnerAdapter implements SpinnerAdapter { UserDetails user = data.get(position); ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(user.mIcon); - ((TextView) row.findViewById(android.R.id.title)).setText(user.mName); + ((TextView) row.findViewById(android.R.id.title)).setText(getTitle(user)); return row; } + private int getTitle(UserDetails user) { + int userHandle = user.mUserHandle.getIdentifier(); + if (userHandle == UserHandle.USER_CURRENT + || userHandle == ActivityManager.getCurrentUser()) { + return R.string.category_personal; + } else { + return R.string.category_work; + } + } + private View createUser(ViewGroup parent) { return mInflater.inflate(R.layout.user_preference, parent, false); } @@ -151,4 +163,14 @@ public class UserSpinnerAdapter implements SpinnerAdapter { public boolean isEmpty() { return data.isEmpty(); } + + @Override + public boolean areAllItemsEnabled() { + return true; + } + + @Override + public boolean isEnabled(int position) { + return true; + } } \ No newline at end of file diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 16037c55e4d..bc6cbedebec 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -75,7 +75,7 @@ import android.widget.ListView; import android.widget.TabWidget; import com.android.internal.util.UserIcons; -import com.android.settings.UserSpinnerAdapter.UserDetails; +import com.android.settings.UserAdapter.UserDetails; import com.android.settings.dashboard.DashboardTile; import com.android.settings.drawable.CircleFramedDrawable; @@ -114,19 +114,19 @@ public final class Utils { * Name of the meta-data item that should be set in the AndroidManifest.xml * to specify the icon that should be displayed for the preference. */ - private static final String META_DATA_PREFERENCE_ICON = "com.android.settings.icon"; + public static final String META_DATA_PREFERENCE_ICON = "com.android.settings.icon"; /** * Name of the meta-data item that should be set in the AndroidManifest.xml * to specify the title that should be displayed for the preference. */ - private static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title"; + public static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title"; /** * Name of the meta-data item that should be set in the AndroidManifest.xml * to specify the summary text that should be displayed for the preference. */ - private static final String META_DATA_PREFERENCE_SUMMARY = "com.android.settings.summary"; + public static final String META_DATA_PREFERENCE_SUMMARY = "com.android.settings.summary"; private static final String SETTINGS_PACKAGE_NAME = "com.android.settings"; @@ -198,14 +198,17 @@ public final class Utils { if (intent != null) { // Find the activity that is in the system image PackageManager pm = context.getPackageManager(); - List list = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA); + List list = tile.userHandle.size() != 0 + ? pm.queryIntentActivitiesAsUser(intent, PackageManager.GET_META_DATA, + tile.userHandle.get(0).getIdentifier()) + : pm.queryIntentActivities(intent, PackageManager.GET_META_DATA); int listSize = list.size(); for (int i = 0; i < listSize; i++) { ResolveInfo resolveInfo = list.get(i); if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - Drawable icon = null; - String title = null; + int icon = 0; + CharSequence title = null; String summary = null; // Get the activity's meta-data @@ -215,14 +218,18 @@ public final class Utils { Bundle metaData = resolveInfo.activityInfo.metaData; if (res != null && metaData != null) { - icon = res.getDrawable( - metaData.getInt(META_DATA_PREFERENCE_ICON), null); - title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE)); - summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY)); + if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) { + icon = metaData.getInt(META_DATA_PREFERENCE_ICON); + } + if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) { + title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE)); + } + if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) { + summary = res.getString( + metaData.getInt(META_DATA_PREFERENCE_SUMMARY)); + } } - } catch (NameNotFoundException e) { - // Ignore - } catch (NotFoundException e) { + } catch (NameNotFoundException | NotFoundException e) { // Ignore } @@ -231,10 +238,13 @@ public final class Utils { if (TextUtils.isEmpty(title)) { title = resolveInfo.loadLabel(pm).toString(); } + if (icon == 0) { + icon = resolveInfo.activityInfo.icon; + } // Set icon, title and summary for the preference - // TODO: - //tile.icon = icon; + tile.iconRes = icon; + tile.iconPkg = resolveInfo.activityInfo.packageName; tile.title = title; tile.summary = summary; // Replace the intent with this specific activity @@ -728,14 +738,14 @@ public final class Utils { } /** - * Creates a {@link UserSpinnerAdapter} if there is more than one profile on the device. + * Creates a {@link UserAdapter} if there is more than one profile on the device. * *

    The adapter can be used to populate a spinner that switches between the Settings * app on the different profiles. * - * @return a {@link UserSpinnerAdapter} or null if there is only one profile. + * @return a {@link UserAdapter} or null if there is only one profile. */ - public static UserSpinnerAdapter createUserSpinnerAdapter(UserManager userManager, + public static UserAdapter createUserSpinnerAdapter(UserManager userManager, Context context) { List userProfiles = userManager.getUserProfiles(); if (userProfiles.size() < 2) { @@ -747,12 +757,17 @@ public final class Utils { userProfiles.remove(myUserHandle); userProfiles.add(0, myUserHandle); + return createUserAdapter(userManager, context, userProfiles); + } + + public static UserAdapter createUserAdapter(UserManager userManager, + Context context, List userProfiles) { ArrayList userDetails = new ArrayList(userProfiles.size()); final int count = userProfiles.size(); for (int i = 0; i < count; i++) { userDetails.add(new UserDetails(userProfiles.get(i), userManager, context)); } - return new UserSpinnerAdapter(context, userDetails); + return new UserAdapter(context, userDetails); } /** diff --git a/src/com/android/settings/dashboard/DashboardCategory.java b/src/com/android/settings/dashboard/DashboardCategory.java index fedbf0abc8d..69d0316f761 100644 --- a/src/com/android/settings/dashboard/DashboardCategory.java +++ b/src/com/android/settings/dashboard/DashboardCategory.java @@ -51,6 +51,16 @@ public class DashboardCategory implements Parcelable { */ public CharSequence title; + /** + * Key used for placing external tiles. + */ + public String key; + + /** + * Optional index of where to place tiles specified by system apps. + */ + public int externalIndex = -1; + /** * List of the category's children */ @@ -105,7 +115,9 @@ public class DashboardCategory implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(titleRes); + dest.writeInt(externalIndex); TextUtils.writeToParcel(title, dest, flags); + dest.writeString(key); final int count = tiles.size(); dest.writeInt(count); @@ -118,7 +130,9 @@ public class DashboardCategory implements Parcelable { public void readFromParcel(Parcel in) { titleRes = in.readInt(); + externalIndex = in.readInt(); title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + key = in.readString(); final int count = in.readInt(); diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java index cf398d7bec5..8a9286036c8 100644 --- a/src/com/android/settings/dashboard/DashboardSummary.java +++ b/src/com/android/settings/dashboard/DashboardSummary.java @@ -21,6 +21,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.os.Bundle; import android.os.Handler; @@ -32,6 +33,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; + import com.android.settings.R; import com.android.settings.SettingsActivity; @@ -148,7 +150,15 @@ public class DashboardSummary extends Fragment { private void updateTileView(Context context, Resources res, DashboardTile tile, ImageView tileIcon, TextView tileTextView, TextView statusTextView) { - if (tile.iconRes > 0) { + if (!TextUtils.isEmpty(tile.iconPkg)) { + try { + tileIcon.setImageDrawable(context.getPackageManager() + .getResourcesForApplication(tile.iconPkg).getDrawable(tile.iconRes, null)); + } catch (NameNotFoundException | Resources.NotFoundException e) { + tileIcon.setImageDrawable(null); + tileIcon.setBackground(null); + } + } else if (tile.iconRes > 0) { tileIcon.setImageResource(tile.iconRes); } else { tileIcon.setImageDrawable(null); diff --git a/src/com/android/settings/dashboard/DashboardTile.java b/src/com/android/settings/dashboard/DashboardTile.java index 1f1d9c2d422..94833d37836 100644 --- a/src/com/android/settings/dashboard/DashboardTile.java +++ b/src/com/android/settings/dashboard/DashboardTile.java @@ -21,8 +21,11 @@ import android.content.res.Resources; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.os.UserHandle; import android.text.TextUtils; +import java.util.ArrayList; + /** * Description of a single dashboard tile that the user can select. */ @@ -72,6 +75,11 @@ public class DashboardTile implements Parcelable { */ public int iconRes; + /** + * Optional package to pull the icon resource from. + */ + public String iconPkg; + /** * Full class name of the fragment to display when this tile is * selected. @@ -90,6 +98,11 @@ public class DashboardTile implements Parcelable { */ public Intent intent; + /** + * Optional list of user handles which the intent should be launched on. + */ + public ArrayList userHandle = new ArrayList<>(); + /** * Optional additional data for use by subclasses of the activity */ @@ -136,6 +149,7 @@ public class DashboardTile implements Parcelable { dest.writeInt(summaryRes); TextUtils.writeToParcel(summary, dest, flags); dest.writeInt(iconRes); + dest.writeString(iconPkg); dest.writeString(fragment); dest.writeBundle(fragmentArguments); if (intent != null) { @@ -144,6 +158,11 @@ public class DashboardTile implements Parcelable { } else { dest.writeInt(0); } + final int N = userHandle.size(); + dest.writeInt(N); + for (int i = 0; i < N; i++) { + dest.writeParcelable(userHandle.get(i), flags); + } dest.writeBundle(extras); } @@ -154,11 +173,16 @@ public class DashboardTile implements Parcelable { summaryRes = in.readInt(); summary = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); iconRes = in.readInt(); + iconPkg = in.readString(); fragment = in.readString(); fragmentArguments = in.readBundle(); if (in.readInt() != 0) { intent = Intent.CREATOR.createFromParcel(in); } + final int N = in.readInt(); + for (int i = 0; i < N; i++) { + userHandle.add(UserHandle.CREATOR.createFromParcel(in)); + } extras = in.readBundle(); } diff --git a/src/com/android/settings/dashboard/DashboardTileView.java b/src/com/android/settings/dashboard/DashboardTileView.java index a54217bc18f..0896b826296 100644 --- a/src/com/android/settings/dashboard/DashboardTileView.java +++ b/src/com/android/settings/dashboard/DashboardTileView.java @@ -16,14 +16,16 @@ package com.android.settings.dashboard; +import android.app.Activity; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; - import android.widget.ImageView; import android.widget.TextView; + +import com.android.settings.ProfileSelectDialog; import com.android.settings.R; import com.android.settings.Utils; @@ -93,7 +95,14 @@ public class DashboardTileView extends FrameLayout implements View.OnClickListen Utils.startWithFragment(getContext(), mTile.fragment, mTile.fragmentArguments, null, 0, mTile.titleRes, mTile.getTitle(getResources())); } else if (mTile.intent != null) { - getContext().startActivity(mTile.intent); + int numUserHandles = mTile.userHandle.size(); + if (numUserHandles > 1) { + ProfileSelectDialog.show(((Activity) getContext()).getFragmentManager(), mTile); + } else if (numUserHandles == 1) { + getContext().startActivityAsUser(mTile.intent, mTile.userHandle.get(0)); + } else { + getContext().startActivity(mTile.intent); + } } } } diff --git a/src/com/android/settings/print/PrintSettingsFragment.java b/src/com/android/settings/print/PrintSettingsFragment.java index 3e989e4a85b..7317d79839c 100644 --- a/src/com/android/settings/print/PrintSettingsFragment.java +++ b/src/com/android/settings/print/PrintSettingsFragment.java @@ -52,13 +52,15 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.Spinner; import android.widget.TextView; import com.android.internal.content.PackageMonitor; -import com.android.settings.UserSpinnerAdapter; import com.android.settings.DialogCreatable; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.UserAdapter; import com.android.settings.Utils; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; @@ -68,9 +70,6 @@ import java.text.DateFormat; import java.util.ArrayList; import java.util.List; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.Spinner; - /** * Fragment with the top level print settings. */ @@ -120,7 +119,7 @@ public class PrintSettingsFragment extends SettingsPreferenceFragment private PreferenceCategory mPrintServicesCategory; private PrintJobsController mPrintJobsController; - private UserSpinnerAdapter mProfileSpinnerAdapter; + private UserAdapter mProfileSpinnerAdapter; private Spinner mSpinner; @Override