1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.shortcut; 18 19 import static com.android.settings.shortcut.Shortcuts.SHORTCUT_ID_PREFIX; 20 import static com.android.settings.shortcut.Shortcuts.SHORTCUT_PROBE; 21 22 import static com.google.common.base.Preconditions.checkNotNull; 23 24 import android.app.Flags; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.pm.PackageManager; 29 import android.content.pm.ResolveInfo; 30 import android.content.pm.ShortcutInfo; 31 import android.content.pm.ShortcutManager; 32 33 import androidx.annotation.NonNull; 34 import androidx.annotation.Nullable; 35 36 import com.android.settings.Settings; 37 38 import java.util.ArrayList; 39 import java.util.List; 40 41 public class ShortcutsUpdater { 42 43 /** 44 * Update label, icon, and intent of pinned shortcuts to Settings subpages. 45 * 46 * <p>Should be called whenever any of those could have changed, such as after changing locale, 47 * restoring a backup from a different device, or when flags controlling available features 48 * may have flipped. 49 */ updatePinnedShortcuts(Context context)50 public static void updatePinnedShortcuts(Context context) { 51 ShortcutManager sm = checkNotNull(context.getSystemService(ShortcutManager.class)); 52 53 List<ShortcutInfo> updates = new ArrayList<>(); 54 for (ShortcutInfo info : sm.getPinnedShortcuts()) { 55 ResolveInfo resolvedActivity = resolveActivity(context, info); 56 if (resolvedActivity != null) { 57 // Id is preserved to update an existing shortcut, but the activity it opens might 58 // be different, according to maybeGetReplacingComponent. 59 updates.add(Shortcuts.createShortcutInfo(context, info.getId(), resolvedActivity)); 60 } 61 } 62 if (!updates.isEmpty()) { 63 sm.updateShortcuts(updates); 64 } 65 } 66 67 @Nullable resolveActivity(Context context, ShortcutInfo shortcut)68 private static ResolveInfo resolveActivity(Context context, ShortcutInfo shortcut) { 69 if (!shortcut.getId().startsWith(SHORTCUT_ID_PREFIX)) { 70 return null; 71 } 72 73 ComponentName cn = ComponentName.unflattenFromString( 74 shortcut.getId().substring(SHORTCUT_ID_PREFIX.length())); 75 if (cn == null) { 76 return null; 77 } 78 79 // Check if the componentName is obsolete and has been replaced by a different one. 80 cn = maybeGetReplacingComponent(context, cn); 81 PackageManager pm = context.getPackageManager(); 82 return pm.resolveActivity(new Intent(SHORTCUT_PROBE).setComponent(cn), 0); 83 } 84 85 @NonNull maybeGetReplacingComponent(Context context, ComponentName cn)86 private static ComponentName maybeGetReplacingComponent(Context context, ComponentName cn) { 87 // ZenModeSettingsActivity is replaced by ModesSettingsActivity and will be deleted 88 // soon (so we shouldn't use ZenModeSettingsActivity.class). 89 if (Flags.modesUi() 90 && cn.getClassName().endsWith("Settings$ZenModeSettingsActivity")) { 91 return new ComponentName(context, Settings.ModesSettingsActivity.class); 92 } 93 94 return cn; 95 } 96 } 97