diff options
Diffstat (limited to 'src')
6 files changed, 274 insertions, 157 deletions
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 00501272cf..99d7d474b0 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -30,6 +30,7 @@ public class Settings extends SettingsActivity { */ public static class AssistGestureSettingsActivity extends SettingsActivity { /* empty */} public static class BluetoothSettingsActivity extends SettingsActivity { /* empty */ } + public static class CreateShortcutActivity extends SettingsActivity { /* empty */ } public static class SimSettingsActivity extends SettingsActivity { /* empty */ } public static class TetherSettingsActivity extends SettingsActivity { /* empty */ } public static class WifiTetherSettingsActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/SettingsInitialize.java b/src/com/android/settings/SettingsInitialize.java index b4b6d73199..a66207e812 100644 --- a/src/com/android/settings/SettingsInitialize.java +++ b/src/com/android/settings/SettingsInitialize.java @@ -34,7 +34,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.Log; -import com.android.settings.shortcut.CreateShortcut; +import com.android.settings.Settings.CreateShortcutActivity; import java.util.ArrayList; import java.util.List; @@ -101,7 +101,8 @@ public class SettingsInitialize extends BroadcastReceiver { pm.setComponentEnabledSetting(settingsComponentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); // Disable shortcut picker. - ComponentName shortcutComponentName = new ComponentName(context, CreateShortcut.class); + ComponentName shortcutComponentName = new ComponentName( + context, CreateShortcutActivity.class); pm.setComponentEnabledSetting(shortcutComponentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); } diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index b486174c55..64afd94240 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -115,6 +115,7 @@ import com.android.settings.print.PrintSettingsFragment; import com.android.settings.security.CryptKeeperSettings; import com.android.settings.security.LockscreenDashboardFragment; import com.android.settings.security.SecuritySettings; +import com.android.settings.shortcut.CreateShortcut; import com.android.settings.sim.SimSettings; import com.android.settings.support.SupportDashboardActivity; import com.android.settings.system.ResetDashboardFragment; @@ -142,6 +143,7 @@ public class SettingsGateway { */ public static final String[] ENTRY_FRAGMENTS = { AdvancedConnectedDeviceDashboardFragment.class.getName(), + CreateShortcut.class.getName(), WifiSettings.class.getName(), ConfigureWifiSettings.class.getName(), SavedAccessPointsWifiSettings.class.getName(), diff --git a/src/com/android/settings/shortcut/CreateShortcut.java b/src/com/android/settings/shortcut/CreateShortcut.java index 15378fd6bc..b5b6438ed5 100644 --- a/src/com/android/settings/shortcut/CreateShortcut.java +++ b/src/com/android/settings/shortcut/CreateShortcut.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2018 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. @@ -16,179 +16,57 @@ package com.android.settings.shortcut; -import android.app.LauncherActivity; -import android.content.ComponentName; +import static com.android.settings.search.actionbar.SearchMenuController + .NEED_SEARCH_ICON_IN_ACTION_BAR; + import android.content.Context; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ShortcutInfo; -import android.content.pm.ShortcutManager; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.Icon; -import android.graphics.drawable.LayerDrawable; -import android.net.ConnectivityManager; -import android.os.AsyncTask; -import android.util.Log; -import android.view.ContextThemeWrapper; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.MeasureSpec; -import android.widget.ImageView; -import android.widget.ListView; +import android.os.Bundle; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; -import com.android.settings.Settings.TetherSettingsActivity; -import com.android.settings.overlay.FeatureFactory; - -import java.util.ArrayList; -import java.util.List; - -import androidx.annotation.VisibleForTesting; +import com.android.settings.dashboard.DashboardFragment; -public class CreateShortcut extends LauncherActivity { +/** + * UI for create widget/shortcut screen. + */ +public class CreateShortcut extends DashboardFragment { private static final String TAG = "CreateShortcut"; - @VisibleForTesting - static final String SHORTCUT_ID_PREFIX = "component-shortcut-"; - - @Override - protected Intent getTargetIntent() { - return getBaseIntent().addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - } @Override - protected void onListItemClick(ListView l, View v, int position, long id) { - final ListItem item = itemForPosition(position); - logCreateShortcut(item.resolveInfo); - setResult(RESULT_OK, createResultIntent(intentForPosition(position), - item.resolveInfo, item.label)); - finish(); - } - - @VisibleForTesting - Intent createResultIntent(Intent shortcutIntent, ResolveInfo resolveInfo, - CharSequence label) { - shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - ShortcutManager sm = getSystemService(ShortcutManager.class); - ActivityInfo activityInfo = resolveInfo.activityInfo; - - Icon maskableIcon = activityInfo.icon != 0 && activityInfo.applicationInfo != null - ? Icon.createWithAdaptiveBitmap( - createIcon(activityInfo.applicationInfo, activityInfo.icon, - R.layout.shortcut_badge_maskable, - getResources().getDimensionPixelSize(R.dimen.shortcut_size_maskable))) - : Icon.createWithResource(this, R.drawable.ic_launcher_settings); - String shortcutId = SHORTCUT_ID_PREFIX + - shortcutIntent.getComponent().flattenToShortString(); - ShortcutInfo info = new ShortcutInfo.Builder(this, shortcutId) - .setShortLabel(label) - .setIntent(shortcutIntent) - .setIcon(maskableIcon) - .build(); - Intent intent = sm.createShortcutResultIntent(info); - if (intent == null) { - intent = new Intent(); - } - intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, - Intent.ShortcutIconResource.fromContext(this, R.mipmap.ic_launcher_settings)); - intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, label); - - if (activityInfo.icon != 0) { - intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, createIcon( - activityInfo.applicationInfo, - activityInfo.icon, - R.layout.shortcut_badge, - getResources().getDimensionPixelSize(R.dimen.shortcut_size))); + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + Bundle args = getArguments(); + if (args == null) { + args = new Bundle(); + setArguments(args); } - return intent; + args.putBoolean(NEED_SEARCH_ICON_IN_ACTION_BAR, false); } - private void logCreateShortcut(ResolveInfo info) { - if (info == null || info.activityInfo == null) { - return; - } - FeatureFactory.getFactory(this).getMetricsFeatureProvider().action( - this, MetricsProto.MetricsEvent.ACTION_SETTINGS_CREATE_SHORTCUT, - info.activityInfo.name); - } - - private Bitmap createIcon(ApplicationInfo app, int resource, int layoutRes, int size) { - final Context context = new ContextThemeWrapper(this, android.R.style.Theme_Material); - final View view = LayoutInflater.from(context).inflate(layoutRes, null); - final int spec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); - view.measure(spec, spec); - final Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), - Config.ARGB_8888); - final Canvas canvas = new Canvas(bitmap); - - Drawable iconDrawable = null; - try { - iconDrawable = - getPackageManager().getResourcesForApplication(app).getDrawable(resource); - if (iconDrawable instanceof LayerDrawable) { - iconDrawable = ((LayerDrawable) iconDrawable).getDrawable(1); - } - ((ImageView) view.findViewById(android.R.id.icon)).setImageDrawable(iconDrawable); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Cannot load icon from app " + app + ", returning a default icon"); - Icon icon = Icon.createWithResource(this, R.drawable.ic_launcher_settings); - ((ImageView) view.findViewById(android.R.id.icon)).setImageIcon(icon); - } - - view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); - view.draw(canvas); - return bitmap; + @Override + public void onAttach(Context context) { + super.onAttach(context); + use(CreateShortcutPreferenceController.class).setActivity(getActivity()); } @Override - protected boolean onEvaluateShowIcons() { - return false; + protected int getPreferenceScreenResId() { + return R.xml.create_shortcut; } @Override - protected void onSetContentView() { - setContentView(R.layout.activity_list); + protected String getLogTag() { + return TAG; } - /** - * Perform query on package manager for list items. The default - * implementation queries for activities. - */ @Override - protected List<ResolveInfo> onQueryPackageManager(Intent queryIntent) { - List<ResolveInfo> activities = getPackageManager().queryIntentActivities(queryIntent, - PackageManager.GET_META_DATA); - final ConnectivityManager cm = - (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - if (activities == null) { - return null; - } - for (int i = activities.size() - 1; i >= 0; i--) { - ResolveInfo info = activities.get(i); - if (info.activityInfo.name.endsWith(TetherSettingsActivity.class.getSimpleName())) { - if (!cm.isTetheringSupported()) { - activities.remove(i); - } - } - if (!info.activityInfo.applicationInfo.isSystemApp()) { - Log.d(TAG, "Skipping non-system app: " + info.activityInfo); - activities.remove(i); - } - } - return activities; + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.SETTINGS_CREATE_SHORTCUT; } - @VisibleForTesting - static Intent getBaseIntent() { - return new Intent(Intent.ACTION_MAIN).addCategory("com.android.settings.SHORTCUT"); + @Override + public int getHelpResource() { + return 0; } - } diff --git a/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java b/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java new file mode 100644 index 0000000000..e995e008ba --- /dev/null +++ b/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2018 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.shortcut; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; +import android.graphics.drawable.LayerDrawable; +import android.net.ConnectivityManager; +import android.util.Log; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.Settings.TetherSettingsActivity; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; + +import java.util.ArrayList; +import java.util.List; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceGroup; + +/** + * {@link BasePreferenceController} that populates a list of widgets that Settings app support. + */ +public class CreateShortcutPreferenceController extends BasePreferenceController { + + private static final String TAG = "CreateShortcutPrefCtrl"; + + static final String SHORTCUT_ID_PREFIX = "component-shortcut-"; + static final Intent SHORTCUT_PROBE = new Intent(Intent.ACTION_MAIN) + .addCategory("com.android.settings.SHORTCUT") + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + private final ShortcutManager mShortcutManager; + private final PackageManager mPackageManager; + private final ConnectivityManager mConnectivityManager; + private final MetricsFeatureProvider mMetricsFeatureProvider; + private Activity mHost; + + public CreateShortcutPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mConnectivityManager = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + mShortcutManager = context.getSystemService(ShortcutManager.class); + mPackageManager = context.getPackageManager(); + mMetricsFeatureProvider = FeatureFactory.getFactory(context) + .getMetricsFeatureProvider(); + } + + public void setActivity(Activity host) { + mHost = host; + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE_UNSEARCHABLE; + } + + @Override + public void updateState(Preference preference) { + if (!(preference instanceof PreferenceGroup)) { + return; + } + final PreferenceGroup group = (PreferenceGroup) preference; + group.removeAll(); + final List<ResolveInfo> shortcuts = queryShortcuts(); + final Context uiContext = preference.getContext(); + for (ResolveInfo info : shortcuts) { + final Preference pref = new Preference(uiContext); + pref.setTitle(info.loadLabel(mPackageManager)); + pref.setOnPreferenceClickListener(clickTarget -> { + if (mHost == null) { + return false; + } + final Intent shortcutIntent = createResultIntent( + buildShortcutIntent(info), + info, clickTarget.getTitle()); + mHost.setResult(Activity.RESULT_OK, shortcutIntent); + logCreateShortcut(info); + mHost.finish(); + return true; + }); + group.addPreference(pref); + } + } + + /** + * Create {@link Intent} that will be consumed by ShortcutManager, which later generates a + * launcher widget using this intent. + */ + @VisibleForTesting + Intent createResultIntent(Intent shortcutIntent, ResolveInfo resolveInfo, + CharSequence label) { + final ActivityInfo activityInfo = resolveInfo.activityInfo; + + final Icon maskableIcon; + if (activityInfo.icon != 0 && activityInfo.applicationInfo != null) { + maskableIcon = Icon.createWithAdaptiveBitmap(createIcon( + activityInfo.applicationInfo, activityInfo.icon, + R.layout.shortcut_badge_maskable, + mContext.getResources().getDimensionPixelSize(R.dimen.shortcut_size_maskable))); + } else { + maskableIcon = Icon.createWithResource(mContext, R.drawable.ic_launcher_settings); + } + final String shortcutId = SHORTCUT_ID_PREFIX + + shortcutIntent.getComponent().flattenToShortString(); + ShortcutInfo info = new ShortcutInfo.Builder(mContext, shortcutId) + .setShortLabel(label) + .setIntent(shortcutIntent) + .setIcon(maskableIcon) + .build(); + Intent intent = mShortcutManager.createShortcutResultIntent(info); + if (intent == null) { + intent = new Intent(); + } + intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, + Intent.ShortcutIconResource.fromContext(mContext, R.mipmap.ic_launcher_settings)) + .putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent) + .putExtra(Intent.EXTRA_SHORTCUT_NAME, label); + + if (activityInfo.icon != 0) { + intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, createIcon( + activityInfo.applicationInfo, + activityInfo.icon, + R.layout.shortcut_badge, + mContext.getResources().getDimensionPixelSize(R.dimen.shortcut_size))); + } + return intent; + } + + /** + * Finds all shortcut supported by Settings. + */ + @VisibleForTesting + List<ResolveInfo> queryShortcuts() { + final List<ResolveInfo> shortcuts = new ArrayList<>(); + final List<ResolveInfo> activities = mPackageManager.queryIntentActivities(SHORTCUT_PROBE, + PackageManager.GET_META_DATA); + + if (activities == null) { + return null; + } + for (ResolveInfo info : activities) { + if (info.activityInfo.name.endsWith(TetherSettingsActivity.class.getSimpleName())) { + if (!mConnectivityManager.isTetheringSupported()) { + continue; + } + } + if (!info.activityInfo.applicationInfo.isSystemApp()) { + Log.d(TAG, "Skipping non-system app: " + info.activityInfo); + continue; + } + shortcuts.add(info); + } + return shortcuts; + } + + private void logCreateShortcut(ResolveInfo info) { + if (info == null || info.activityInfo == null) { + return; + } + mMetricsFeatureProvider.action( + mContext, MetricsProto.MetricsEvent.ACTION_SETTINGS_CREATE_SHORTCUT, + info.activityInfo.name); + } + + private Intent buildShortcutIntent(ResolveInfo info) { + return new Intent(SHORTCUT_PROBE) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP) + .setClassName(info.activityInfo.packageName, info.activityInfo.name); + } + + private Bitmap createIcon(ApplicationInfo app, int resource, int layoutRes, int size) { + final Context context = new ContextThemeWrapper(mContext, android.R.style.Theme_Material); + final View view = LayoutInflater.from(context).inflate(layoutRes, null); + final int spec = View.MeasureSpec.makeMeasureSpec(size, View.MeasureSpec.EXACTLY); + view.measure(spec, spec); + final Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), + Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(bitmap); + + Drawable iconDrawable; + try { + iconDrawable = mPackageManager.getResourcesForApplication(app).getDrawable(resource); + if (iconDrawable instanceof LayerDrawable) { + iconDrawable = ((LayerDrawable) iconDrawable).getDrawable(1); + } + ((ImageView) view.findViewById(android.R.id.icon)).setImageDrawable(iconDrawable); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Cannot load icon from app " + app + ", returning a default icon"); + Icon icon = Icon.createWithResource(mContext, R.drawable.ic_launcher_settings); + ((ImageView) view.findViewById(android.R.id.icon)).setImageIcon(icon); + } + + view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); + view.draw(canvas); + return bitmap; + } +} diff --git a/src/com/android/settings/shortcut/ShortcutsUpdateTask.java b/src/com/android/settings/shortcut/ShortcutsUpdateTask.java index 5144fe11f1..54f7d1ceaf 100644 --- a/src/com/android/settings/shortcut/ShortcutsUpdateTask.java +++ b/src/com/android/settings/shortcut/ShortcutsUpdateTask.java @@ -16,8 +16,12 @@ package com.android.settings.shortcut; +import static com.android.settings.shortcut.CreateShortcutPreferenceController.SHORTCUT_ID_PREFIX; +import static com.android.settings.shortcut.CreateShortcutPreferenceController.SHORTCUT_PROBE; + import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; @@ -42,12 +46,12 @@ public class ShortcutsUpdateTask extends AsyncTask<Void, Void, Void> { List<ShortcutInfo> updates = new ArrayList<>(); for (ShortcutInfo info : sm.getPinnedShortcuts()) { - if (!info.getId().startsWith(CreateShortcut.SHORTCUT_ID_PREFIX)) { + if (!info.getId().startsWith(SHORTCUT_ID_PREFIX)) { continue; } ComponentName cn = ComponentName.unflattenFromString( - info.getId().substring(CreateShortcut.SHORTCUT_ID_PREFIX.length())); - ResolveInfo ri = pm.resolveActivity(CreateShortcut.getBaseIntent().setComponent(cn), 0); + info.getId().substring(SHORTCUT_ID_PREFIX.length())); + ResolveInfo ri = pm.resolveActivity(new Intent(SHORTCUT_PROBE).setComponent(cn), 0); if (ri == null) { continue; } |