summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--SecondaryDisplayLauncher/res/values-zh-rTW/strings.xml2
-rw-r--r--go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java53
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java16
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java6
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java10
-rw-r--r--quickstep/src/com/android/quickstep/RecentTasksList.java21
-rw-r--r--quickstep/src/com/android/quickstep/RecentsModel.java6
-rw-r--r--quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java8
-rw-r--r--quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java98
-rw-r--r--res/values-hi/strings.xml2
-rw-r--r--robolectric_tests/src/com/android/launcher3/util/IntArrayTest.java38
-rw-r--r--robolectric_tests/src/com/android/launcher3/util/IntSetTest.java1
-rw-r--r--src/com/android/launcher3/AbstractFloatingView.java2
-rw-r--r--src/com/android/launcher3/AutoInstallsLayout.java3
-rw-r--r--src/com/android/launcher3/BaseDraggingActivity.java8
-rw-r--r--src/com/android/launcher3/InstallShortcutReceiver.java2
-rw-r--r--src/com/android/launcher3/Launcher.java16
-rw-r--r--src/com/android/launcher3/LauncherProvider.java6
-rw-r--r--src/com/android/launcher3/Partner.java4
-rw-r--r--src/com/android/launcher3/Utilities.java132
-rw-r--r--src/com/android/launcher3/logging/FileLog.java5
-rw-r--r--src/com/android/launcher3/model/AddWorkspaceItemsTask.java4
-rw-r--r--src/com/android/launcher3/model/LoaderTask.java10
-rw-r--r--src/com/android/launcher3/model/UserLockStateChangedTask.java5
-rw-r--r--src/com/android/launcher3/provider/ImportDataTask.java4
-rw-r--r--src/com/android/launcher3/provider/RestoreDbTask.java11
-rw-r--r--src/com/android/launcher3/util/IOUtils.java16
-rw-r--r--src/com/android/launcher3/util/IntArray.java12
-rw-r--r--src/com/android/launcher3/util/PackageManagerHelper.java72
-rw-r--r--src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java76
-rw-r--r--tests/src/com/android/launcher3/model/LoaderCursorTest.java6
31 files changed, 393 insertions, 262 deletions
diff --git a/SecondaryDisplayLauncher/res/values-zh-rTW/strings.xml b/SecondaryDisplayLauncher/res/values-zh-rTW/strings.xml
index bf76f29de..c02fe2cdc 100644
--- a/SecondaryDisplayLauncher/res/values-zh-rTW/strings.xml
+++ b/SecondaryDisplayLauncher/res/values-zh-rTW/strings.xml
@@ -21,5 +21,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="couldnt_launch" msgid="7873588052226763866">"無法啟動活動"</string>
<string name="add_app_shortcut" msgid="2756755330707509435">"新增應用程式捷徑"</string>
- <string name="set_wallpaper" msgid="6475195450505435904">"設定桌布"</string>
+ <string name="set_wallpaper" msgid="6475195450505435904">"套用桌布"</string>
</resources>
diff --git a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
index 1e449108d..c20ed129c 100644
--- a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
+++ b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
@@ -26,57 +26,46 @@ import android.os.UserHandle;
import com.android.launcher3.ItemInfo;
-import java.util.Collections;
+import java.util.ArrayList;
import java.util.List;
/**
* Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
*/
public class DeepShortcutManager {
- private static DeepShortcutManager sInstance;
- private static final Object sInstanceLock = new Object();
+
+ private static final DeepShortcutManager sInstance = new DeepShortcutManager();
public static DeepShortcutManager getInstance(Context context) {
- synchronized (sInstanceLock) {
- if (sInstance == null) {
- sInstance = new DeepShortcutManager(context.getApplicationContext());
- }
- return sInstance;
- }
+ return sInstance;
}
- private DeepShortcutManager(Context context) {
- }
+ private final QueryResult mFailure = new QueryResult();
- public static boolean supportsShortcuts(ItemInfo info) {
- return false;
- }
+ private DeepShortcutManager() { }
- public boolean wasLastCallSuccess() {
+ public static boolean supportsShortcuts(ItemInfo info) {
return false;
}
- public void onShortcutsChanged(List<ShortcutInfo> shortcuts) {
- }
-
/**
* Queries for the shortcuts with the package name and provided ids.
*
* This method is intended to get the full details for shortcuts when they are added or updated,
* because we only get "key" fields in onShortcutsChanged().
*/
- public List<ShortcutInfo> queryForFullDetails(String packageName,
+ public QueryResult queryForFullDetails(String packageName,
List<String> shortcutIds, UserHandle user) {
- return Collections.emptyList();
+ return mFailure;
}
/**
* Gets all the manifest and dynamic shortcuts associated with the given package and user,
* to be displayed in the shortcuts container on long press.
*/
- public List<ShortcutInfo> queryForShortcutsContainer(ComponentName activity,
+ public QueryResult queryForShortcutsContainer(ComponentName activity,
UserHandle user) {
- return Collections.emptyList();
+ return mFailure;
}
/**
@@ -106,20 +95,28 @@ public class DeepShortcutManager {
*
* If packageName is null, returns all pinned shortcuts regardless of package.
*/
- public List<ShortcutInfo> queryForPinnedShortcuts(String packageName, UserHandle user) {
- return Collections.emptyList();
+ public QueryResult queryForPinnedShortcuts(String packageName, UserHandle user) {
+ return mFailure;
}
- public List<ShortcutInfo> queryForPinnedShortcuts(String packageName,
+ public QueryResult queryForPinnedShortcuts(String packageName,
List<String> shortcutIds, UserHandle user) {
- return Collections.emptyList();
+ return mFailure;
}
- public List<ShortcutInfo> queryForAllShortcuts(UserHandle user) {
- return Collections.emptyList();
+ public QueryResult queryForAllShortcuts(UserHandle user) {
+ return mFailure;
}
public boolean hasHostPermission() {
return false;
}
+
+
+ public static class QueryResult extends ArrayList<ShortcutInfo> {
+
+ public boolean wasSuccess() {
+ return true;
+ }
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java
index 8f1282ded..fe0d16017 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java
@@ -170,10 +170,10 @@ public class PredictionAppTracker extends AppLaunchTracker {
public void onStartShortcut(String packageName, String shortcutId, UserHandle user,
String container) {
// TODO: Use the full shortcut info
- AppTarget target = new AppTarget
- .Builder(new AppTargetId("shortcut:" + shortcutId), packageName, user)
- .setClassName(shortcutId)
- .build();
+ AppTarget target = new AppTarget.Builder(
+ new AppTargetId("shortcut:" + shortcutId), packageName, user)
+ .setClassName(shortcutId)
+ .build();
sendLaunch(target, container);
}
@@ -181,10 +181,10 @@ public class PredictionAppTracker extends AppLaunchTracker {
@UiThread
public void onStartApp(ComponentName cn, UserHandle user, String container) {
if (cn != null) {
- AppTarget target = new AppTarget
- .Builder(new AppTargetId("app:" + cn), cn.getPackageName(), user)
- .setClassName(cn.getClassName())
- .build();
+ AppTarget target = new AppTarget.Builder(
+ new AppTargetId("app:" + cn), cn.getPackageName(), user)
+ .setClassName(cn.getClassName())
+ .build();
sendLaunch(target, container);
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
index f08ae4a82..9bdc98bf8 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
@@ -136,6 +136,12 @@ public final class RecentsActivity extends BaseRecentsActivity {
}
@Override
+ public void returnToHomescreen() {
+ super.returnToHomescreen();
+ // TODO(b/137318995) This should go home, but doing so removes freeform windows
+ }
+
+ @Override
public ActivityOptions getActivityLaunchOptions(final View v) {
if (!(v instanceof TaskView)) {
return null;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java
index 213c5d324..cfd14bb29 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java
@@ -36,8 +36,6 @@ import android.view.View;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
@@ -268,12 +266,16 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
@Override
protected ActivityOptions makeLaunchOptions(Activity activity) {
- return ActivityOptionsCompat.makeFreeformOptions();
+ ActivityOptions activityOptions = ActivityOptionsCompat.makeFreeformOptions();
+ // Arbitrary bounds only because freeform is in dev mode right now
+ Rect r = new Rect(50, 50, 200, 200);
+ activityOptions.setLaunchBounds(r);
+ return activityOptions;
}
@Override
protected boolean onActivityStarted(BaseDraggingActivity activity) {
- Launcher.getLauncher(activity).getStateManager().goToState(LauncherState.NORMAL);
+ activity.returnToHomescreen();
return true;
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index e41dba94c..71ce32b28 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -20,10 +20,12 @@ import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR;
import android.annotation.TargetApi;
import android.app.ActivityManager;
-import android.content.Context;
import android.os.Build;
import android.os.Process;
import android.util.SparseBooleanArray;
+
+import androidx.annotation.VisibleForTesting;
+
import com.android.launcher3.MainThreadExecutor;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -42,6 +44,7 @@ public class RecentTasksList extends TaskStackChangeListener {
private final KeyguardManagerCompat mKeyguardManager;
private final MainThreadExecutor mMainThreadExecutor;
+ private final ActivityManagerWrapper mActivityManagerWrapper;
// The list change id, increments as the task list changes in the system
private int mChangeId;
@@ -52,11 +55,14 @@ public class RecentTasksList extends TaskStackChangeListener {
ArrayList<Task> mTasks = new ArrayList<>();
- public RecentTasksList(Context context) {
- mMainThreadExecutor = new MainThreadExecutor();
- mKeyguardManager = new KeyguardManagerCompat(context);
+
+ public RecentTasksList(MainThreadExecutor mainThreadExecutor,
+ KeyguardManagerCompat keyguardManager, ActivityManagerWrapper activityManagerWrapper) {
+ mMainThreadExecutor = mainThreadExecutor;
+ mKeyguardManager = keyguardManager;
mChangeId = 1;
- ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
+ mActivityManagerWrapper = activityManagerWrapper;
+ mActivityManagerWrapper.registerTaskStackListener(this);
}
/**
@@ -136,12 +142,13 @@ public class RecentTasksList extends TaskStackChangeListener {
/**
* Loads and creates a list of all the recent tasks.
*/
- private ArrayList<Task> loadTasksInBackground(int numTasks,
+ @VisibleForTesting
+ ArrayList<Task> loadTasksInBackground(int numTasks,
boolean loadKeysOnly) {
int currentUserId = Process.myUserHandle().getIdentifier();
ArrayList<Task> allTasks = new ArrayList<>();
List<ActivityManager.RecentTaskInfo> rawTasks =
- ActivityManagerWrapper.getInstance().getRecentTasks(numTasks, currentUserId);
+ mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId);
// The raw tasks are given in most-recent to least-recent order, we need to reverse it
Collections.reverse(rawTasks);
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 9f1248458..650169cf3 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -30,11 +30,14 @@ import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
+import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.BackgroundExecutor;
+import com.android.systemui.shared.system.KeyguardManagerCompat;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
@@ -68,7 +71,8 @@ public class RecentsModel extends TaskStackChangeListener {
HandlerThread loaderThread = new HandlerThread("TaskThumbnailIconCache",
Process.THREAD_PRIORITY_BACKGROUND);
loaderThread.start();
- mTaskList = new RecentTasksList(context);
+ mTaskList = new RecentTasksList(new MainThreadExecutor(),
+ new KeyguardManagerCompat(context), ActivityManagerWrapper.getInstance());
mIconCache = new TaskIconCache(context, loaderThread.getLooper());
mThumbnailCache = new TaskThumbnailCache(context, loaderThread.getLooper());
ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
diff --git a/quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java b/quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java
index d0956d1f6..7801775d4 100644
--- a/quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java
+++ b/quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java
@@ -150,10 +150,10 @@ public class AppPredictionsUITests extends AbstractQuickStepTest {
List<AppTarget> targets = new ArrayList<>(activities.length);
for (LauncherActivityInfo info : activities) {
ComponentName cn = info.getComponentName();
- AppTarget target =
- new AppTarget.Builder(new AppTargetId("app:" + cn), cn.getPackageName(), info.getUser())
- .setClassName(cn.getClassName())
- .build();
+ AppTarget target = new AppTarget.Builder(
+ new AppTargetId("app:" + cn), cn.getPackageName(), info.getUser())
+ .setClassName(cn.getClassName())
+ .build();
targets.add(target);
}
mCallback.onTargetsAvailable(targets);
diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
new file mode 100644
index 000000000..5fb27bcc6
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 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.quickstep;
+
+import android.app.ActivityManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.MainThreadExecutor;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.KeyguardManagerCompat;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.List;
+
+import static junit.framework.TestCase.assertNull;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@SmallTest
+public class RecentTasksListTest {
+
+ private ActivityManagerWrapper mockActivityManagerWrapper;
+
+ // Class under test
+ private RecentTasksList mRecentTasksList;
+
+ @Before
+ public void setup() {
+ MainThreadExecutor mockMainThreadExecutor = mock(MainThreadExecutor.class);
+ KeyguardManagerCompat mockKeyguardManagerCompat = mock(KeyguardManagerCompat.class);
+ mockActivityManagerWrapper = mock(ActivityManagerWrapper.class);
+ mRecentTasksList = new RecentTasksList(mockMainThreadExecutor, mockKeyguardManagerCompat,
+ mockActivityManagerWrapper);
+ }
+
+ @Test
+ public void onTaskRemoved_reloadsAllTasks() {
+ mRecentTasksList.onTaskRemoved(0);
+ verify(mockActivityManagerWrapper, times(1))
+ .getRecentTasks(anyInt(), anyInt());
+ }
+
+ @Test
+ public void onTaskStackChanged_doesNotFetchTasks() {
+ mRecentTasksList.onTaskStackChanged();
+ verify(mockActivityManagerWrapper, times(0))
+ .getRecentTasks(anyInt(), anyInt());
+ }
+
+ @Test
+ public void loadTasksInBackground_onlyKeys_noValidTaskDescription() {
+ ActivityManager.RecentTaskInfo recentTaskInfo = new ActivityManager.RecentTaskInfo();
+ when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt()))
+ .thenReturn(Collections.singletonList(recentTaskInfo));
+
+ List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, true);
+
+ assertEquals(1, taskList.size());
+ assertNull(taskList.get(0).taskDescription.getLabel());
+ }
+
+ @Test
+ public void loadTasksInBackground_moreThanKeys_hasValidTaskDescription() {
+ String taskDescription = "Wheeee!";
+ ActivityManager.RecentTaskInfo recentTaskInfo = new ActivityManager.RecentTaskInfo();
+ recentTaskInfo.taskDescription = new ActivityManager.TaskDescription(taskDescription);
+ when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt()))
+ .thenReturn(Collections.singletonList(recentTaskInfo));
+
+ List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, false);
+
+ assertEquals(1, taskList.size());
+ assertEquals(taskDescription, taskList.get(0).taskDescription.getLabel());
+ }
+}
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index b796140e5..3b0432ee4 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -88,7 +88,7 @@
<string name="notification_dots_title" msgid="9062440428204120317">"नई सूचनाएं बताने वाला गोल निशान"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"चालू"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"चालू"</string>
- <string name="title_missing_notification_access" msgid="7503287056163941064">"सूचना के एक्सेस की ज़रूरत है"</string>
+ <string name="title_missing_notification_access" msgid="7503287056163941064">"सूचना के ऐक्सेस की ज़रूरत है"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"सूचना बिंदु दिखाने के लिए, <xliff:g id="NAME">%1$s</xliff:g> के ऐप्लिकेशन सूचना चालू करें"</string>
<string name="title_change_settings" msgid="1376365968844349552">"सेटिंग बदलें"</string>
<string name="notification_dots_service_title" msgid="4284221181793592871">"नई सूचनाएं बताने वाला गोल निशान दिखाएं"</string>
diff --git a/robolectric_tests/src/com/android/launcher3/util/IntArrayTest.java b/robolectric_tests/src/com/android/launcher3/util/IntArrayTest.java
new file mode 100644
index 000000000..c08e198a8
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/util/IntArrayTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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.launcher3.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+/**
+ * Robolectric unit tests for {@link IntArray}
+ */
+@RunWith(RobolectricTestRunner.class)
+public class IntArrayTest {
+
+ @Test
+ public void concatAndParseString() {
+ int[] array = new int[] {0, 2, 3, 9};
+ String concat = IntArray.wrap(array).toConcatString();
+
+ int[] parsed = IntArray.fromConcatString(concat).toArray();
+ assertThat(array).isEqualTo(parsed);
+ }
+}
diff --git a/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java b/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java
index f846de5e5..8513353dc 100644
--- a/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java
+++ b/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java
@@ -21,7 +21,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 65f9d6bc0..8fddf3cff 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -86,7 +86,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
// Type of popups which should be kept open during launcher rebind
public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
- | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE;
+ | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE;
// Usually we show the back button when a floating view is open. Instead, hide for these types.
public static final int TYPE_HIDE_BACK_BUTTON = TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 9724869bf..9db694944 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -43,6 +43,7 @@ import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Thunk;
import org.xmlpull.v1.XmlPullParser;
@@ -72,7 +73,7 @@ public class AutoInstallsLayout {
static AutoInstallsLayout get(Context context, AppWidgetHost appWidgetHost,
LayoutParserCallback callback) {
- Pair<String, Resources> customizationApkInfo = Utilities.findSystemApk(
+ Pair<String, Resources> customizationApkInfo = PackageManagerHelper.findSystemApk(
ACTION_LAUNCHER_CUSTOMIZATION, context.getPackageManager());
if (customizationApkInfo == null) {
return null;
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 50553095d..8de00691e 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -34,9 +34,9 @@ import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.shortcuts.DeepShortcutManager;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.uioverrides.DisplayRotationListener;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
+import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Themes;
import androidx.annotation.Nullable;
@@ -120,6 +120,10 @@ public abstract class BaseDraggingActivity extends BaseActivity
public abstract View getRootView();
+ public void returnToHomescreen() {
+ // no-op
+ }
+
public Rect getViewBounds(View v) {
int[] pos = new int[2];
v.getLocationOnScreen(pos);
@@ -135,7 +139,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item,
@Nullable String sourceContainer) {
- if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
+ if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return false;
}
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index e9b932aaf..a6b53b92d 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -612,7 +612,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
// Already an activity target
return original;
}
- if (!Utilities.isLauncherAppTarget(original.launchIntent)) {
+ if (!PackageManagerHelper.isLauncherAppTarget(original.launchIntent)) {
return original;
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 03fdc971d..40d76681b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -20,6 +20,8 @@ import static android.content.pm.ActivityInfo.CONFIG_LOCALE;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -1426,9 +1428,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
outState.remove(RUNTIME_STATE_WIDGET_PANEL);
}
- // We close any open folders and shortcut containers since they will not be re-opened,
+ // We close any open folders and shortcut containers that are not safe for rebind,
// and we need to make sure this state is reflected.
- AbstractFloatingView.closeAllOpenViews(this, false);
+ AbstractFloatingView.closeOpenViews(this, false, TYPE_ALL & ~TYPE_REBIND_SAFE);
+ finishAutoCancelActionMode();
if (mPendingRequestArgs != null) {
outState.putParcelable(RUNTIME_STATE_PENDING_REQUEST_ARGS, mPendingRequestArgs);
@@ -1909,8 +1912,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
// Floating panels (except the full widget sheet) are associated with individual icons. If
// we are starting a fresh bind, close all such panels as all the icons are about
// to go away.
- AbstractFloatingView.closeOpenViews(this, true,
- AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
+ AbstractFloatingView.closeOpenViews(this, true, TYPE_ALL & ~TYPE_REBIND_SAFE);
setWorkspaceLoading(true);
@@ -2566,6 +2568,12 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
return (Launcher) fromContext(context);
}
+ @Override
+ public void returnToHomescreen() {
+ super.returnToHomescreen();
+ getStateManager().goToState(LauncherState.NORMAL);
+ }
+
/**
* Just a wrapper around the type cast to allow easier tracking of calls.
*/
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 6ad5c3684..6081300ce 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -33,7 +33,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.OperationApplicationException;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ProviderInfo;
import android.content.res.Resources;
import android.database.Cursor;
@@ -50,7 +49,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.Process;
import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.BaseColumns;
import android.provider.Settings;
import android.text.TextUtils;
@@ -70,6 +68,7 @@ import com.android.launcher3.util.IOUtils;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.NoLocaleSQLiteHelper;
+import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.Thunk;
@@ -77,7 +76,6 @@ import org.xmlpull.v1.XmlPullParser;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringReader;
@@ -873,7 +871,7 @@ public class LauncherProvider extends ContentProvider {
continue;
}
- if (!Utilities.isLauncherAppTarget(intent)) {
+ if (!PackageManagerHelper.isLauncherAppTarget(intent)) {
continue;
}
diff --git a/src/com/android/launcher3/Partner.java b/src/com/android/launcher3/Partner.java
index 380078b26..af5402ae2 100644
--- a/src/com/android/launcher3/Partner.java
+++ b/src/com/android/launcher3/Partner.java
@@ -16,6 +16,8 @@
package com.android.launcher3;
+import static com.android.launcher3.util.PackageManagerHelper.findSystemApk;
+
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.util.DisplayMetrics;
@@ -59,7 +61,7 @@ public class Partner {
*/
public static synchronized Partner get(PackageManager pm) {
if (!sSearched) {
- Pair<String, Resources> apkInfo = Utilities.findSystemApk(ACTION_PARTNER_CUSTOMIZATION, pm);
+ Pair<String, Resources> apkInfo = findSystemApk(ACTION_PARTNER_CUSTOMIZATION, pm);
if (apkInfo != null) {
sPartner = new Partner(apkInfo.first, apkInfo.second);
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index fc5cd8a88..80305228b 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -23,15 +23,9 @@ import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
@@ -46,7 +40,6 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
-import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Message;
@@ -59,7 +52,6 @@ import android.text.TextUtils;
import android.text.style.TtsSpan;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.Pair;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
@@ -68,7 +60,6 @@ import android.view.animation.Interpolator;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.graphics.TintedDrawableSpan;
@@ -80,13 +71,10 @@ import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.Transposable;
import com.android.launcher3.widget.PendingAddShortcutInfo;
-import java.io.Closeable;
-import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
-import java.util.StringTokenizer;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
@@ -243,7 +231,6 @@ public final class Utilities {
return scale;
}
-
/**
* Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, float[], boolean)}.
*/
@@ -379,53 +366,6 @@ public final class Utilities {
return min + (value * (max - min));
}
- public static boolean isSystemApp(Context context, Intent intent) {
- PackageManager pm = context.getPackageManager();
- ComponentName cn = intent.getComponent();
- String packageName = null;
- if (cn == null) {
- ResolveInfo info = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
- if ((info != null) && (info.activityInfo != null)) {
- packageName = info.activityInfo.packageName;
- }
- } else {
- packageName = cn.getPackageName();
- }
- if (packageName != null) {
- try {
- PackageInfo info = pm.getPackageInfo(packageName, 0);
- return (info != null) && (info.applicationInfo != null) &&
- ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
- } catch (NameNotFoundException e) {
- return false;
- }
- } else {
- return false;
- }
- }
-
- /*
- * Finds a system apk which had a broadcast receiver listening to a particular action.
- * @param action intent action used to find the apk
- * @return a pair of apk package name and the resources.
- */
- static Pair<String, Resources> findSystemApk(String action, PackageManager pm) {
- final Intent intent = new Intent(action);
- for (ResolveInfo info : pm.queryBroadcastReceivers(intent, 0)) {
- if (info.activityInfo != null &&
- (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- final String packageName = info.activityInfo.packageName;
- try {
- final Resources res = pm.getResourcesForApplication(packageName);
- return Pair.create(packageName, res);
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Failed to find resources for " + packageName);
- }
- }
- }
- return null;
- }
-
/**
* Trims the string, removing all whitespace at the beginning and end of the string.
* Non-breaking whitespaces are also removed.
@@ -450,51 +390,10 @@ public final class Utilities {
return (int) Math.ceil(fm.bottom - fm.top);
}
- /**
- * Convenience println with multiple args.
- */
- public static void println(String key, Object... args) {
- StringBuilder b = new StringBuilder();
- b.append(key);
- b.append(": ");
- boolean isFirstArgument = true;
- for (Object arg : args) {
- if (isFirstArgument) {
- isFirstArgument = false;
- } else {
- b.append(", ");
- }
- b.append(arg);
- }
- System.out.println(b.toString());
- }
-
public static boolean isRtl(Resources res) {
return res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}
- /**
- * Returns true if the intent is a valid launch intent for a launcher activity of an app.
- * This is used to identify shortcuts which are different from the ones exposed by the
- * applications' manifest file.
- *
- * @param launchIntent The intent that will be launched when the shortcut is clicked.
- */
- public static boolean isLauncherAppTarget(Intent launchIntent) {
- if (launchIntent != null
- && Intent.ACTION_MAIN.equals(launchIntent.getAction())
- && launchIntent.getComponent() != null
- && launchIntent.getCategories() != null
- && launchIntent.getCategories().size() == 1
- && launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER)
- && TextUtils.isEmpty(launchIntent.getDataString())) {
- // An app target can either have no extra or have ItemInfo.EXTRA_PROFILE.
- Bundle extras = launchIntent.getExtras();
- return extras == null || extras.keySet().isEmpty();
- }
- return false;
- }
-
public static float dpiFromPx(int size, DisplayMetrics metrics){
float densityRatio = (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
return (size / densityRatio);
@@ -597,18 +496,6 @@ public final class Utilities {
return context.getSystemService(WallpaperManager.class).isSetWallpaperAllowed();
}
- public static void closeSilently(Closeable c) {
- if (c != null) {
- try {
- c.close();
- } catch (IOException e) {
- if (FeatureFlags.IS_DOGFOOD_BUILD) {
- Log.d(TAG, "Error closing", e);
- }
- }
- }
- }
-
public static boolean isBinderSizeError(Exception e) {
return e.getCause() instanceof TransactionTooLargeException
|| e.getCause() instanceof DeadObjectException;
@@ -723,25 +610,6 @@ public final class Utilities {
}
}
- public static int[] getIntArrayFromString(String tokenized) {
- StringTokenizer tokenizer = new StringTokenizer(tokenized, ",");
- int[] array = new int[tokenizer.countTokens()];
- int count = 0;
- while (tokenizer.hasMoreTokens()) {
- array[count] = Integer.parseInt(tokenizer.nextToken());
- count++;
- }
- return array;
- }
-
- public static String getStringFromIntArray(int[] array) {
- StringBuilder str = new StringBuilder();
- for (int value : array) {
- str.append(value).append(",");
- }
- return str.toString();
- }
-
public static float squaredHypot(float x, float y) {
return x * x + y * y;
}
diff --git a/src/com/android/launcher3/logging/FileLog.java b/src/com/android/launcher3/logging/FileLog.java
index f7f8ef18f..cc920767f 100644
--- a/src/com/android/launcher3/logging/FileLog.java
+++ b/src/com/android/launcher3/logging/FileLog.java
@@ -8,6 +8,7 @@ import android.util.Pair;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.IOUtils;
import java.io.BufferedReader;
import java.io.File;
@@ -131,7 +132,7 @@ public final class FileLog {
private PrintWriter mCurrentWriter = null;
private void closeWriter() {
- Utilities.closeSilently(mCurrentWriter);
+ IOUtils.closeSilently(mCurrentWriter);
mCurrentWriter = null;
}
@@ -219,7 +220,7 @@ public final class FileLog {
} catch (Exception e) {
// ignore
} finally {
- Utilities.closeSilently(in);
+ IOUtils.closeSilently(in);
}
}
}
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index ed0d47080..8c264c186 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -31,9 +31,9 @@ import com.android.launcher3.LauncherModel.CallbackTask;
import com.android.launcher3.LauncherModel.Callbacks;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.WorkspaceItemInfo;
-import com.android.launcher3.Utilities;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.PackageManagerHelper;
import java.util.ArrayList;
import java.util.List;
@@ -162,7 +162,7 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
intentWithoutPkg = intent.toUri(0);
}
- boolean isLauncherAppTarget = Utilities.isLauncherAppTarget(intent);
+ boolean isLauncherAppTarget = PackageManagerHelper.isLauncherAppTarget(intent);
synchronized (dataModel) {
for (ItemInfo item : dataModel.itemsIdMap) {
if (item instanceof WorkspaceItemInfo) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 0138572d0..6c3394669 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -20,6 +20,7 @@ import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
import static com.android.launcher3.model.LoaderResults.filterCurrentWorkspaceItems;
+import static com.android.launcher3.util.PackageManagerHelper.isSystemApp;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
@@ -69,6 +70,7 @@ import com.android.launcher3.provider.ImportDataTask;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.IOUtils;
import com.android.launcher3.util.LooperIdleLock;
import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
@@ -317,9 +319,9 @@ public class LoaderTask implements Runnable {
// We can only query for shortcuts when the user is unlocked.
if (userUnlocked) {
- List<ShortcutInfo> pinnedShortcuts =
+ DeepShortcutManager.QueryResult pinnedShortcuts =
mShortcutManager.queryForPinnedShortcuts(null, user);
- if (mShortcutManager.wasLastCallSuccess()) {
+ if (pinnedShortcuts.wasSuccess()) {
for (ShortcutInfo shortcut : pinnedShortcuts) {
shortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
shortcut);
@@ -531,7 +533,7 @@ public class LoaderTask implements Runnable {
info.spanX = 1;
info.spanY = 1;
info.runtimeStatusFlags |= disabledState;
- if (isSafeMode && !Utilities.isSystemApp(context, intent)) {
+ if (isSafeMode && !isSystemApp(context, intent)) {
info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE;
}
@@ -703,7 +705,7 @@ public class LoaderTask implements Runnable {
}
}
} finally {
- Utilities.closeSilently(c);
+ IOUtils.closeSilently(c);
}
// Break early if we've stopped loading
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 2cb256e09..50fff2653 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -37,7 +37,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
/**
* Task to handle changing of lock state of the user
@@ -58,9 +57,9 @@ public class UserLockStateChangedTask extends BaseModelUpdateTask {
HashMap<ShortcutKey, ShortcutInfo> pinnedShortcuts = new HashMap<>();
if (isUserUnlocked) {
- List<ShortcutInfo> shortcuts =
+ DeepShortcutManager.QueryResult shortcuts =
deepShortcutManager.queryForPinnedShortcuts(null, mUser);
- if (deepShortcutManager.wasLastCallSuccess()) {
+ if (shortcuts.wasSuccess()) {
for (ShortcutInfo shortcut : shortcuts) {
pinnedShortcuts.put(ShortcutKey.fromInfo(shortcut), shortcut);
}
diff --git a/src/com/android/launcher3/provider/ImportDataTask.java b/src/com/android/launcher3/provider/ImportDataTask.java
index 7b62f53fe..970a03e80 100644
--- a/src/com/android/launcher3/provider/ImportDataTask.java
+++ b/src/com/android/launcher3/provider/ImportDataTask.java
@@ -42,7 +42,6 @@ import com.android.launcher3.LauncherProvider;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.LauncherSettings.Settings;
-import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
@@ -50,6 +49,7 @@ import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.GridSizeMigrationTask;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.util.PackageManagerHelper;
import java.net.URISyntaxException;
import java.util.ArrayList;
@@ -223,7 +223,7 @@ public class ImportDataTask {
case Favorites.ITEM_TYPE_SHORTCUT:
case Favorites.ITEM_TYPE_APPLICATION: {
intent = Intent.parseUri(c.getString(intentIndex), 0);
- if (Utilities.isLauncherAppTarget(intent)) {
+ if (PackageManagerHelper.isLauncherAppTarget(intent)) {
type = Favorites.ITEM_TYPE_APPLICATION;
} else {
values.put(Favorites.ICON_PACKAGE, c.getString(iconPackageIndex));
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 3c0c5fdde..0a2d4e3d3 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -16,8 +16,6 @@
package com.android.launcher3.provider;
-import static com.android.launcher3.Utilities.getIntArrayFromString;
-import static com.android.launcher3.Utilities.getStringFromIntArray;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import android.app.backup.BackupManager;
@@ -40,6 +38,7 @@ import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
+import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.LogConfig;
import java.io.InvalidObjectException;
@@ -246,8 +245,8 @@ public class RestoreDbTask {
SharedPreferences prefs = Utilities.getPrefs(context);
if (prefs.contains(APPWIDGET_OLD_IDS) && prefs.contains(APPWIDGET_IDS)) {
AppWidgetsRestoredReceiver.restoreAppWidgetIds(context,
- getIntArrayFromString(prefs.getString(APPWIDGET_OLD_IDS, "")),
- getIntArrayFromString(prefs.getString(APPWIDGET_IDS, "")));
+ IntArray.fromConcatString(prefs.getString(APPWIDGET_OLD_IDS, "")).toArray(),
+ IntArray.fromConcatString(prefs.getString(APPWIDGET_IDS, "")).toArray());
} else {
FileLog.d(TAG, "No app widget ids to restore.");
}
@@ -259,8 +258,8 @@ public class RestoreDbTask {
public static void setRestoredAppWidgetIds(Context context, @NonNull int[] oldIds,
@NonNull int[] newIds) {
Utilities.getPrefs(context).edit()
- .putString(APPWIDGET_OLD_IDS, getStringFromIntArray(oldIds))
- .putString(APPWIDGET_IDS, getStringFromIntArray(newIds))
+ .putString(APPWIDGET_OLD_IDS, IntArray.wrap(oldIds).toConcatString())
+ .putString(APPWIDGET_IDS, IntArray.wrap(newIds).toConcatString())
.commit();
}
diff --git a/src/com/android/launcher3/util/IOUtils.java b/src/com/android/launcher3/util/IOUtils.java
index f95f74d60..4a4a5ca22 100644
--- a/src/com/android/launcher3/util/IOUtils.java
+++ b/src/com/android/launcher3/util/IOUtils.java
@@ -17,10 +17,13 @@
package com.android.launcher3.util;
import android.content.Context;
+import android.util.Log;
+import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -35,6 +38,7 @@ import java.util.UUID;
public class IOUtils {
private static final int BUF_SIZE = 0x1000; // 4K
+ private static final String TAG = "IOUtils";
public static byte[] toByteArray(File file) throws IOException {
try (InputStream in = new FileInputStream(file)) {
@@ -77,4 +81,16 @@ public class IOUtils {
}
return file.getAbsolutePath();
}
+
+ public static void closeSilently(Closeable c) {
+ if (c != null) {
+ try {
+ c.close();
+ } catch (IOException e) {
+ if (FeatureFlags.IS_DOGFOOD_BUILD) {
+ Log.d(TAG, "Error closing", e);
+ }
+ }
+ }
+ }
}
diff --git a/src/com/android/launcher3/util/IntArray.java b/src/com/android/launcher3/util/IntArray.java
index d2a551f45..7252f7ac1 100644
--- a/src/com/android/launcher3/util/IntArray.java
+++ b/src/com/android/launcher3/util/IntArray.java
@@ -17,6 +17,7 @@
package com.android.launcher3.util;
import java.util.Arrays;
+import java.util.StringTokenizer;
/**
* Copy of the platform hidden implementation of android.util.IntArray.
@@ -248,6 +249,17 @@ public class IntArray implements Cloneable {
return b.toString();
}
+ public static IntArray fromConcatString(String concatString) {
+ StringTokenizer tokenizer = new StringTokenizer(concatString, ",");
+ int[] array = new int[tokenizer.countTokens()];
+ int count = 0;
+ while (tokenizer.hasMoreTokens()) {
+ array[count] = Integer.parseInt(tokenizer.nextToken().trim());
+ count++;
+ }
+ return new IntArray(array, array.length);
+ }
+
/**
* Throws {@link ArrayIndexOutOfBoundsException} if the index is out of bounds.
*
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 7d3a94162..ef4307ec5 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -24,9 +24,11 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
@@ -35,6 +37,7 @@ import android.os.PatternMatcher;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import android.widget.Toast;
import com.android.launcher3.AppInfo;
@@ -220,4 +223,73 @@ public class PackageManagerHelper {
packageFilter.addDataSchemeSpecificPart(pkg, PatternMatcher.PATTERN_LITERAL);
return packageFilter;
}
+
+ public static boolean isSystemApp(Context context, Intent intent) {
+ PackageManager pm = context.getPackageManager();
+ ComponentName cn = intent.getComponent();
+ String packageName = null;
+ if (cn == null) {
+ ResolveInfo info = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if ((info != null) && (info.activityInfo != null)) {
+ packageName = info.activityInfo.packageName;
+ }
+ } else {
+ packageName = cn.getPackageName();
+ }
+ if (packageName != null) {
+ try {
+ PackageInfo info = pm.getPackageInfo(packageName, 0);
+ return (info != null) && (info.applicationInfo != null) &&
+ ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Finds a system apk which had a broadcast receiver listening to a particular action.
+ * @param action intent action used to find the apk
+ * @return a pair of apk package name and the resources.
+ */
+ public static Pair<String, Resources> findSystemApk(String action, PackageManager pm) {
+ final Intent intent = new Intent(action);
+ for (ResolveInfo info : pm.queryBroadcastReceivers(intent, 0)) {
+ if (info.activityInfo != null &&
+ (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ final String packageName = info.activityInfo.packageName;
+ try {
+ final Resources res = pm.getResourcesForApplication(packageName);
+ return Pair.create(packageName, res);
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Failed to find resources for " + packageName);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if the intent is a valid launch intent for a launcher activity of an app.
+ * This is used to identify shortcuts which are different from the ones exposed by the
+ * applications' manifest file.
+ *
+ * @param launchIntent The intent that will be launched when the shortcut is clicked.
+ */
+ public static boolean isLauncherAppTarget(Intent launchIntent) {
+ if (launchIntent != null
+ && Intent.ACTION_MAIN.equals(launchIntent.getAction())
+ && launchIntent.getComponent() != null
+ && launchIntent.getCategories() != null
+ && launchIntent.getCategories().size() == 1
+ && launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER)
+ && TextUtils.isEmpty(launchIntent.getDataString())) {
+ // An app target can either have no extra or have ItemInfo.EXTRA_PROFILE.
+ Bundle extras = launchIntent.getExtras();
+ return extras == null || extras.keySet().isEmpty();
+ }
+ return false;
+ }
}
diff --git a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java
index 6b6f70d7b..84a59b228 100644
--- a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java
+++ b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java
@@ -45,19 +45,15 @@ public class DeepShortcutManager {
| ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_PINNED;
private static DeepShortcutManager sInstance;
- private static final Object sInstanceLock = new Object();
public static DeepShortcutManager getInstance(Context context) {
- synchronized (sInstanceLock) {
- if (sInstance == null) {
- sInstance = new DeepShortcutManager(context.getApplicationContext());
- }
- return sInstance;
+ if (sInstance == null) {
+ sInstance = new DeepShortcutManager(context.getApplicationContext());
}
+ return sInstance;
}
private final LauncherApps mLauncherApps;
- private boolean mWasLastCallSuccess;
private DeepShortcutManager(Context context) {
mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
@@ -70,17 +66,13 @@ public class DeepShortcutManager {
&& !info.isDisabled() && !isItemPromise;
}
- public boolean wasLastCallSuccess() {
- return mWasLastCallSuccess;
- }
-
/**
* Queries for the shortcuts with the package name and provided ids.
*
* This method is intended to get the full details for shortcuts when they are added or updated,
* because we only get "key" fields in onShortcutsChanged().
*/
- public List<ShortcutInfo> queryForFullDetails(String packageName,
+ public QueryResult queryForFullDetails(String packageName,
List<String> shortcutIds, UserHandle user) {
return query(FLAG_GET_ALL, packageName, null, shortcutIds, user);
}
@@ -89,7 +81,7 @@ public class DeepShortcutManager {
* Gets all the manifest and dynamic shortcuts associated with the given package and user,
* to be displayed in the shortcuts container on long press.
*/
- public List<ShortcutInfo> queryForShortcutsContainer(ComponentName activity,
+ public QueryResult queryForShortcutsContainer(ComponentName activity,
UserHandle user) {
return query(ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_DYNAMIC,
activity.getPackageName(), activity, null, user);
@@ -107,10 +99,8 @@ public class DeepShortcutManager {
pinnedIds.remove(id);
try {
mLauncherApps.pinShortcuts(packageName, pinnedIds, user);
- mWasLastCallSuccess = true;
} catch (SecurityException|IllegalStateException e) {
Log.w(TAG, "Failed to unpin shortcut", e);
- mWasLastCallSuccess = false;
}
}
@@ -126,10 +116,8 @@ public class DeepShortcutManager {
pinnedIds.add(id);
try {
mLauncherApps.pinShortcuts(packageName, pinnedIds, user);
- mWasLastCallSuccess = true;
} catch (SecurityException|IllegalStateException e) {
Log.w(TAG, "Failed to pin shortcut", e);
- mWasLastCallSuccess = false;
}
}
@@ -138,23 +126,18 @@ public class DeepShortcutManager {
try {
mLauncherApps.startShortcut(packageName, id, sourceBounds,
startActivityOptions, user);
- mWasLastCallSuccess = true;
} catch (SecurityException|IllegalStateException e) {
Log.e(TAG, "Failed to start shortcut", e);
- mWasLastCallSuccess = false;
}
}
public Drawable getShortcutIconDrawable(ShortcutInfo shortcutInfo, int density) {
try {
- Drawable icon = mLauncherApps.getShortcutIconDrawable(shortcutInfo, density);
- mWasLastCallSuccess = true;
- return icon;
+ return mLauncherApps.getShortcutIconDrawable(shortcutInfo, density);
} catch (SecurityException|IllegalStateException e) {
Log.e(TAG, "Failed to get shortcut icon", e);
- mWasLastCallSuccess = false;
+ return null;
}
- return null;
}
/**
@@ -162,20 +145,20 @@ public class DeepShortcutManager {
*
* If packageName is null, returns all pinned shortcuts regardless of package.
*/
- public List<ShortcutInfo> queryForPinnedShortcuts(String packageName, UserHandle user) {
+ public QueryResult queryForPinnedShortcuts(String packageName, UserHandle user) {
return queryForPinnedShortcuts(packageName, null, user);
}
- public List<ShortcutInfo> queryForPinnedShortcuts(String packageName,
- List<String> shortcutIds, UserHandle user) {
+ public QueryResult queryForPinnedShortcuts(String packageName, List<String> shortcutIds,
+ UserHandle user) {
return query(ShortcutQuery.FLAG_MATCH_PINNED, packageName, null, shortcutIds, user);
}
- public List<ShortcutInfo> queryForAllShortcuts(UserHandle user) {
+ public QueryResult queryForAllShortcuts(UserHandle user) {
return query(FLAG_GET_ALL, null, null, null, user);
}
- private List<String> extractIds(List<ShortcutInfo> shortcuts) {
+ private static List<String> extractIds(List<ShortcutInfo> shortcuts) {
List<String> shortcutIds = new ArrayList<>(shortcuts.size());
for (ShortcutInfo shortcut : shortcuts) {
shortcutIds.add(shortcut.getId());
@@ -189,8 +172,8 @@ public class DeepShortcutManager {
*
* TODO: Use the cache to optimize this so we don't make an RPC every time.
*/
- private List<ShortcutInfo> query(int flags, String packageName,
- ComponentName activity, List<String> shortcutIds, UserHandle user) {
+ private QueryResult query(int flags, String packageName, ComponentName activity,
+ List<String> shortcutIds, UserHandle user) {
ShortcutQuery q = new ShortcutQuery();
q.setQueryFlags(flags);
if (packageName != null) {
@@ -198,18 +181,12 @@ public class DeepShortcutManager {
q.setActivity(activity);
q.setShortcutIds(shortcutIds);
}
- List<ShortcutInfo> shortcutInfos = null;
try {
- shortcutInfos = mLauncherApps.getShortcuts(q, user);
- mWasLastCallSuccess = true;
+ return new QueryResult(mLauncherApps.getShortcuts(q, user));
} catch (SecurityException|IllegalStateException e) {
Log.e(TAG, "Failed to query for shortcuts", e);
- mWasLastCallSuccess = false;
+ return QueryResult.FAILURE;
}
- if (shortcutInfos == null) {
- return Collections.EMPTY_LIST;
- }
- return shortcutInfos;
}
public boolean hasHostPermission() {
@@ -220,4 +197,25 @@ public class DeepShortcutManager {
}
return false;
}
+
+ public static class QueryResult extends ArrayList<ShortcutInfo> {
+
+ static QueryResult FAILURE = new QueryResult();
+
+ private final boolean mWasSuccess;
+
+ QueryResult(List<ShortcutInfo> result) {
+ super(result == null ? Collections.emptyList() : result);
+ mWasSuccess = true;
+ }
+
+ QueryResult() {
+ mWasSuccess = false;
+ }
+
+
+ public boolean wasSuccess() {
+ return mWasSuccess;
+ }
+ }
}
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
index 7d60ad65b..64df8e0e9 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -15,9 +15,9 @@ import com.android.launcher3.icons.IconCache;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.Utilities;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.util.PackageManagerHelper;
import org.junit.Before;
import org.junit.Test;
@@ -115,7 +115,7 @@ public class LoaderCursorTest {
WorkspaceItemInfo info = mLoaderCursor.getAppShortcutInfo(
new Intent().setComponent(cn), false /* allowMissingTarget */, true);
assertNotNull(info);
- assertTrue(Utilities.isLauncherAppTarget(info.intent));
+ assertTrue(PackageManagerHelper.isLauncherAppTarget(info.intent));
}
@Test
@@ -127,7 +127,7 @@ public class LoaderCursorTest {
WorkspaceItemInfo info = mLoaderCursor.getAppShortcutInfo(
new Intent().setComponent(cn), true /* allowMissingTarget */, true);
assertNotNull(info);
- assertTrue(Utilities.isLauncherAppTarget(info.intent));
+ assertTrue(PackageManagerHelper.isLauncherAppTarget(info.intent));
}
@Test