Convert CreateShortcut to DashboardFragment

Created a new xml and CreateShortcutPreferenceController to deal with
querying package manager and display list on UI.

Bug: 74806595
Test: robotests
Change-Id: I0945245c3856d12b7751d26fca324d2dbf31b230
This commit is contained in:
Fan Zhang
2018-06-22 10:40:07 -07:00
parent 1693bc9d71
commit f1f0f8bea6
13 changed files with 333 additions and 229 deletions

View File

@@ -148,12 +148,15 @@
android:taskAffinity="com.android.settings" android:taskAffinity="com.android.settings"
android:parentActivityName="Settings" /> android:parentActivityName="Settings" />
<activity android:name=".shortcut.CreateShortcut" <activity android:name=".Settings$CreateShortcutActivity"
android:label="@string/settings_shortcut"> android:label="@string/settings_shortcut">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" /> <action android:name="android.intent.action.CREATE_SHORTCUT" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<meta-data
android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.shortcut.CreateShortcut" />
</activity> </activity>
<!-- Wireless Controls --> <!-- Wireless Controls -->

View File

@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/activity_list_empty"
android:visibility="gone"
android:textAppearance="?android:attr/textAppearanceMedium"/>
</FrameLayout>

View File

@@ -689,8 +689,6 @@
<string name="settings_label_launcher">Settings</string> <string name="settings_label_launcher">Settings</string>
<!-- Label for option to select a settings panel as a shortcut --> <!-- Label for option to select a settings panel as a shortcut -->
<string name="settings_shortcut">Settings shortcut</string> <string name="settings_shortcut">Settings shortcut</string>
<!-- Shown in create shortcut activity when there is no shortcut that can be created. [CHAR_LIMIT=None] -->
<string name="activity_list_empty">No matching activities found.</string>
<!-- Wireless controls settings screen, setting check box label --> <!-- Wireless controls settings screen, setting check box label -->
<string name="airplane_mode">Airplane mode</string> <string name="airplane_mode">Airplane mode</string>
<!-- Main Settings screen settings title for things like airplane mode, tethering, NFC, VPN. This will take you to another screen with those settings. [CHAR LIMIT=30] --> <!-- Main Settings screen settings title for things like airplane mode, tethering, NFC, VPN. This will take you to another screen with those settings. [CHAR LIMIT=30] -->

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/settings_shortcut"
android:key="create_shortcut_screen"
settings:controller="com.android.settings.shortcut.CreateShortcutPreferenceController" />

View File

@@ -30,6 +30,7 @@ public class Settings extends SettingsActivity {
*/ */
public static class AssistGestureSettingsActivity extends SettingsActivity { /* empty */} public static class AssistGestureSettingsActivity extends SettingsActivity { /* empty */}
public static class BluetoothSettingsActivity 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 SimSettingsActivity extends SettingsActivity { /* empty */ }
public static class TetherSettingsActivity extends SettingsActivity { /* empty */ } public static class TetherSettingsActivity extends SettingsActivity { /* empty */ }
public static class WifiTetherSettingsActivity extends SettingsActivity { /* empty */ } public static class WifiTetherSettingsActivity extends SettingsActivity { /* empty */ }

View File

@@ -34,7 +34,7 @@ import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.util.Log; import android.util.Log;
import com.android.settings.shortcut.CreateShortcut; import com.android.settings.Settings.CreateShortcutActivity;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -101,7 +101,8 @@ public class SettingsInitialize extends BroadcastReceiver {
pm.setComponentEnabledSetting(settingsComponentName, pm.setComponentEnabledSetting(settingsComponentName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
// Disable shortcut picker. // Disable shortcut picker.
ComponentName shortcutComponentName = new ComponentName(context, CreateShortcut.class); ComponentName shortcutComponentName = new ComponentName(
context, CreateShortcutActivity.class);
pm.setComponentEnabledSetting(shortcutComponentName, pm.setComponentEnabledSetting(shortcutComponentName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
} }

View File

@@ -115,6 +115,7 @@ import com.android.settings.print.PrintSettingsFragment;
import com.android.settings.security.CryptKeeperSettings; import com.android.settings.security.CryptKeeperSettings;
import com.android.settings.security.LockscreenDashboardFragment; import com.android.settings.security.LockscreenDashboardFragment;
import com.android.settings.security.SecuritySettings; import com.android.settings.security.SecuritySettings;
import com.android.settings.shortcut.CreateShortcut;
import com.android.settings.sim.SimSettings; import com.android.settings.sim.SimSettings;
import com.android.settings.support.SupportDashboardActivity; import com.android.settings.support.SupportDashboardActivity;
import com.android.settings.system.ResetDashboardFragment; import com.android.settings.system.ResetDashboardFragment;
@@ -142,6 +143,7 @@ public class SettingsGateway {
*/ */
public static final String[] ENTRY_FRAGMENTS = { public static final String[] ENTRY_FRAGMENTS = {
AdvancedConnectedDeviceDashboardFragment.class.getName(), AdvancedConnectedDeviceDashboardFragment.class.getName(),
CreateShortcut.class.getName(),
WifiSettings.class.getName(), WifiSettings.class.getName(),
ConfigureWifiSettings.class.getName(), ConfigureWifiSettings.class.getName(),
SavedAccessPointsWifiSettings.class.getName(), SavedAccessPointsWifiSettings.class.getName(),

View File

@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,179 +16,57 @@
package com.android.settings.shortcut; package com.android.settings.shortcut;
import android.app.LauncherActivity; import static com.android.settings.search.actionbar.SearchMenuController
import android.content.ComponentName; .NEED_SEARCH_ICON_IN_ACTION_BAR;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.os.Bundle;
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 com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Settings.TetherSettingsActivity; import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.VisibleForTesting;
public class CreateShortcut extends LauncherActivity {
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)));
}
return intent;
}
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
protected boolean onEvaluateShowIcons() {
return false;
}
@Override
protected void onSetContentView() {
setContentView(R.layout.activity_list);
}
/** /**
* Perform query on package manager for list items. The default * UI for create widget/shortcut screen.
* implementation queries for activities.
*/ */
public class CreateShortcut extends DashboardFragment {
private static final String TAG = "CreateShortcut";
@Override @Override
protected List<ResolveInfo> onQueryPackageManager(Intent queryIntent) { public void onCreate(Bundle icicle) {
List<ResolveInfo> activities = getPackageManager().queryIntentActivities(queryIntent, super.onCreate(icicle);
PackageManager.GET_META_DATA); Bundle args = getArguments();
final ConnectivityManager cm = if (args == null) {
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); args = new Bundle();
if (activities == null) { setArguments(args);
return null;
} }
for (int i = activities.size() - 1; i >= 0; i--) { args.putBoolean(NEED_SEARCH_ICON_IN_ACTION_BAR, false);
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;
} }
@VisibleForTesting @Override
static Intent getBaseIntent() { public void onAttach(Context context) {
return new Intent(Intent.ACTION_MAIN).addCategory("com.android.settings.SHORTCUT"); super.onAttach(context);
use(CreateShortcutPreferenceController.class).setActivity(getActivity());
} }
@Override
protected int getPreferenceScreenResId() {
return R.xml.create_shortcut;
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.SETTINGS_CREATE_SHORTCUT;
}
@Override
public int getHelpResource() {
return 0;
}
} }

View File

@@ -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;
}
}

View File

@@ -16,8 +16,12 @@
package com.android.settings.shortcut; 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.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutInfo;
@@ -42,12 +46,12 @@ public class ShortcutsUpdateTask extends AsyncTask<Void, Void, Void> {
List<ShortcutInfo> updates = new ArrayList<>(); List<ShortcutInfo> updates = new ArrayList<>();
for (ShortcutInfo info : sm.getPinnedShortcuts()) { for (ShortcutInfo info : sm.getPinnedShortcuts()) {
if (!info.getId().startsWith(CreateShortcut.SHORTCUT_ID_PREFIX)) { if (!info.getId().startsWith(SHORTCUT_ID_PREFIX)) {
continue; continue;
} }
ComponentName cn = ComponentName.unflattenFromString( ComponentName cn = ComponentName.unflattenFromString(
info.getId().substring(CreateShortcut.SHORTCUT_ID_PREFIX.length())); info.getId().substring(SHORTCUT_ID_PREFIX.length()));
ResolveInfo ri = pm.resolveActivity(CreateShortcut.getBaseIntent().setComponent(cn), 0); ResolveInfo ri = pm.resolveActivity(new Intent(SHORTCUT_PROBE).setComponent(cn), 0);
if (ri == null) { if (ri == null) {
continue; continue;
} }

View File

@@ -5,6 +5,7 @@ com.android.settings.bluetooth.BluetoothDeviceDetailsFragment
com.android.settings.bluetooth.BluetoothPairingDetail com.android.settings.bluetooth.BluetoothPairingDetail
com.android.settings.accounts.AccountDetailDashboardFragment com.android.settings.accounts.AccountDetailDashboardFragment
com.android.settings.accounts.ManagedProfileSettings com.android.settings.accounts.ManagedProfileSettings
com.android.settings.shortcut.CreateShortcut
com.android.settings.fuelgauge.PowerUsageAnomalyDetails com.android.settings.fuelgauge.PowerUsageAnomalyDetails
com.android.settings.fuelgauge.AdvancedPowerUsageDetail com.android.settings.fuelgauge.AdvancedPowerUsageDetail
com.android.settings.development.featureflags.FeatureFlagsDashboard com.android.settings.development.featureflags.FeatureFlagsDashboard

View File

@@ -16,7 +16,7 @@
package com.android.settings.shortcut; package com.android.settings.shortcut;
import static com.android.settings.shortcut.CreateShortcut.SHORTCUT_ID_PREFIX; import static com.android.settings.shortcut.CreateShortcutPreferenceController.SHORTCUT_ID_PREFIX;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any; import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
@@ -44,7 +45,6 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow; import org.robolectric.shadow.api.Shadow;
@@ -54,41 +54,44 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
* Tests for {@link CreateShortcutTest} * Tests for {@link CreateShortcutPreferenceController}
*/ */
@RunWith(SettingsRobolectricTestRunner.class) @RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = ShadowConnectivityManager.class) @Config(shadows = ShadowConnectivityManager.class)
public class CreateShortcutTest { public class CreateShortcutPreferenceControllerTest {
@Mock
private ShortcutManager mShortcutManager;
@Mock
private Activity mHost;
private Context mContext; private Context mContext;
private ShadowConnectivityManager mShadowConnectivityManager; private ShadowConnectivityManager mShadowConnectivityManager;
private ShadowPackageManager mPackageManager; private ShadowPackageManager mPackageManager;
private CreateShortcutPreferenceController mController;
@Mock
private ShortcutManager mShortcutManager;
@Before @Before
public void setup() { public void setup() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application; mContext = spy(RuntimeEnvironment.application);
doReturn(mShortcutManager).when(mContext).getSystemService(eq(Context.SHORTCUT_SERVICE));
mPackageManager = Shadow.extract(mContext.getPackageManager()); mPackageManager = Shadow.extract(mContext.getPackageManager());
mShadowConnectivityManager = ShadowConnectivityManager.getShadow(); mShadowConnectivityManager = ShadowConnectivityManager.getShadow();
mShadowConnectivityManager.setTetheringSupported(true); mShadowConnectivityManager.setTetheringSupported(true);
mController = new CreateShortcutPreferenceController(mContext, "key");
mController.setActivity(mHost);
} }
@Test @Test
public void createResultIntent() { public void createResultIntent() {
CreateShortcut orgActivity = Robolectric.setupActivity(CreateShortcut.class);
CreateShortcut activity = spy(orgActivity);
doReturn(mShortcutManager).when(activity).getSystemService(eq(Context.SHORTCUT_SERVICE));
when(mShortcutManager.createShortcutResultIntent(any(ShortcutInfo.class))) when(mShortcutManager.createShortcutResultIntent(any(ShortcutInfo.class)))
.thenReturn(new Intent().putExtra("d1", "d2")); .thenReturn(new Intent().putExtra("d1", "d2"));
final Intent intent = CreateShortcut.getBaseIntent() final Intent intent = new Intent(CreateShortcutPreferenceController.SHORTCUT_PROBE)
.setClass(activity, Settings.ManageApplicationsActivity.class); .setClass(mContext, Settings.ManageApplicationsActivity.class);
final ResolveInfo ri = activity.getPackageManager().resolveActivity(intent, 0); final ResolveInfo ri = mContext.getPackageManager().resolveActivity(intent, 0);
final Intent result = activity.createResultIntent(intent, ri, "dummy"); final Intent result = mController.createResultIntent(intent, ri, "dummy");
assertThat(result.getStringExtra("d1")).isEqualTo("d2"); assertThat(result.getStringExtra("d1")).isEqualTo("d2");
assertThat((Object) result.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT)).isNotNull(); assertThat((Object) result.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT)).isNotNull();
@@ -113,18 +116,12 @@ public class CreateShortcutTest {
ri2.activityInfo.applicationInfo = new ApplicationInfo(); ri2.activityInfo.applicationInfo = new ApplicationInfo();
ri2.activityInfo.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM; ri2.activityInfo.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
mPackageManager.addResolveInfoForIntent(CreateShortcut.getBaseIntent(), mPackageManager.addResolveInfoForIntent(
new Intent(CreateShortcutPreferenceController.SHORTCUT_PROBE),
Arrays.asList(ri1, ri2)); Arrays.asList(ri1, ri2));
TestClass orgActivity = Robolectric.setupActivity(TestClass.class); final List<ResolveInfo> info = mController.queryShortcuts();
TestClass activity = spy(orgActivity);
List<ResolveInfo> info = activity.onQueryPackageManager(CreateShortcut.getBaseIntent());
assertThat(info).hasSize(1); assertThat(info).hasSize(1);
assertThat(info.get(0)).isEqualTo(ri2); assertThat(info.get(0)).isEqualTo(ri2);
} }
private static class TestClass extends CreateShortcut {
}
} }

View File

@@ -16,7 +16,7 @@
package com.android.settings.shortcut; package com.android.settings.shortcut;
import static com.android.settings.shortcut.CreateShortcut.SHORTCUT_ID_PREFIX; import static com.android.settings.shortcut.CreateShortcutPreferenceController.SHORTCUT_ID_PREFIX;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
@@ -63,7 +63,6 @@ public class ShortcutsUpdateTaskTest {
@Captor @Captor
private ArgumentCaptor<List<ShortcutInfo>> mListCaptor; private ArgumentCaptor<List<ShortcutInfo>> mListCaptor;
@Before @Before
public void setup() { public void setup() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
@@ -75,11 +74,13 @@ public class ShortcutsUpdateTaskTest {
public void shortcutsUpdateTask() { public void shortcutsUpdateTask() {
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
doReturn(mShortcutManager).when(mContext).getSystemService(eq(Context.SHORTCUT_SERVICE)); doReturn(mShortcutManager).when(mContext).getSystemService(eq(Context.SHORTCUT_SERVICE));
final Intent shortcut1 = CreateShortcut.getBaseIntent().setComponent( final Intent shortcut1 = new Intent(CreateShortcutPreferenceController.SHORTCUT_PROBE)
new ComponentName(mContext, Settings.ManageApplicationsActivity.class)); .setComponent(new ComponentName(
mContext, Settings.ManageApplicationsActivity.class));
final ResolveInfo ri1 = mock(ResolveInfo.class); final ResolveInfo ri1 = mock(ResolveInfo.class);
final Intent shortcut2 = CreateShortcut.getBaseIntent().setComponent( final Intent shortcut2 = new Intent(CreateShortcutPreferenceController.SHORTCUT_PROBE)
new ComponentName(mContext, Settings.SoundSettingsActivity.class)); .setComponent(new ComponentName(
mContext, Settings.SoundSettingsActivity.class));
final ResolveInfo ri2 = mock(ResolveInfo.class); final ResolveInfo ri2 = mock(ResolveInfo.class);
when(ri1.loadLabel(any(PackageManager.class))).thenReturn("label1"); when(ri1.loadLabel(any(PackageManager.class))).thenReturn("label1");
when(ri2.loadLabel(any(PackageManager.class))).thenReturn("label2"); when(ri2.loadLabel(any(PackageManager.class))).thenReturn("label2");