Merge "Fix a potential concurrency issue for loading CDB file Bug: 158919530" into ub-launcher3-rvc-dev
diff --git a/Android.mk b/Android.mk
index fcd4a94..7805b32 100644
--- a/Android.mk
+++ b/Android.mk
@@ -67,7 +67,10 @@
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
$(call all-java-files-under, src_shortcuts_overrides) \
- $(call all-java-files-under, src_ui_overrides)
+ $(call all-java-files-under, src_ui_overrides) \
+ $(call all-java-files-under, ext_tests/src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/ext_tests/res
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
# Proguard is disable for testing. Derivarive prjects to keep proguard enabled
diff --git a/ext_tests/res/values/overrides.xml b/ext_tests/res/values/overrides.xml
new file mode 100644
index 0000000..3f071d4
--- /dev/null
+++ b/ext_tests/res/values/overrides.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="test_information_handler_class" translatable="false">com.android.launcher3.testing.DebugTestInformationHandler</string>
+</resources>
+
diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
new file mode 100644
index 0000000..b84c7aa
--- /dev/null
+++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2020 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.testing;
+
+import static android.graphics.Bitmap.Config.ARGB_8888;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.Debug;
+import android.system.Os;
+import android.view.View;
+
+import androidx.annotation.Keep;
+
+import java.util.LinkedList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Class to handle requests from tests, including debug ones.
+ */
+public class DebugTestInformationHandler extends TestInformationHandler {
+ private static LinkedList sLeaks;
+
+ public DebugTestInformationHandler(Context context) {
+ init(context);
+ }
+
+ private static void runGcAndFinalizersSync() {
+ Runtime.getRuntime().gc();
+ Runtime.getRuntime().runFinalization();
+
+ final CountDownLatch fence = new CountDownLatch(1);
+ createFinalizationObserver(fence);
+ try {
+ do {
+ Runtime.getRuntime().gc();
+ Runtime.getRuntime().runFinalization();
+ } while (!fence.await(100, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ // Create the observer in the scope of a method to minimize the chance that
+ // it remains live in a DEX/machine register at the point of the fence guard.
+ // This must be kept to avoid R8 inlining it.
+ @Keep
+ private static void createFinalizationObserver(CountDownLatch fence) {
+ new Object() {
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ fence.countDown();
+ } finally {
+ super.finalize();
+ }
+ }
+ };
+ }
+
+ @Override
+ public Bundle call(String method) {
+ final Bundle response = new Bundle();
+ switch (method) {
+ case TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS: {
+ return getLauncherUIProperty(Bundle::putInt,
+ l -> l.getAppsView().getAppsStore().getDeferUpdatesFlags());
+ }
+
+ case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
+ TestProtocol.sDebugTracing = true;
+ return response;
+
+ case TestProtocol.REQUEST_DISABLE_DEBUG_TRACING:
+ TestProtocol.sDebugTracing = false;
+ return response;
+
+ case TestProtocol.REQUEST_PID: {
+ response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, Os.getpid());
+ return response;
+ }
+
+ case TestProtocol.REQUEST_TOTAL_PSS_KB: {
+ runGcAndFinalizersSync();
+ Debug.MemoryInfo mem = new Debug.MemoryInfo();
+ Debug.getMemoryInfo(mem);
+ response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, mem.getTotalPss());
+ return response;
+ }
+
+ case TestProtocol.REQUEST_JAVA_LEAK: {
+ if (sLeaks == null) sLeaks = new LinkedList();
+
+ // Allocate and dirty the memory.
+ final int leakSize = 1024 * 1024;
+ final byte[] bytes = new byte[leakSize];
+ for (int i = 0; i < leakSize; i += 239) {
+ bytes[i] = (byte) (i % 256);
+ }
+ sLeaks.add(bytes);
+ return response;
+ }
+
+ case TestProtocol.REQUEST_NATIVE_LEAK: {
+ if (sLeaks == null) sLeaks = new LinkedList();
+
+ // Allocate and dirty a bitmap.
+ final Bitmap bitmap = Bitmap.createBitmap(512, 512, ARGB_8888);
+ bitmap.eraseColor(Color.RED);
+ sLeaks.add(bitmap);
+ return response;
+ }
+
+ case TestProtocol.REQUEST_VIEW_LEAK: {
+ if (sLeaks == null) sLeaks = new LinkedList();
+ sLeaks.add(new View(mContext));
+ return response;
+ }
+
+ default:
+ return super.call(method);
+ }
+ }
+}
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 00b0951..e49f2ec 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -22,11 +22,16 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.android.launcher3" >
+ <permission
+ android:name="${packageName}.permission.HOTSEAT_EDU"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signatureOrSystem" />
+
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+ <uses-permission android:name="${packageName}.permission.HOTSEAT_EDU" />
-
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
android:fullBackupOnly="true"
@@ -105,6 +110,18 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
+ <activity
+ android:name=".hybridhotseat.HotseatEduActivity"
+ android:theme="@android:style/Theme.NoDisplay"
+ android:noHistory="true"
+ android:launchMode="singleTask"
+ android:clearTaskOnLaunch="true"
+ android:permission="${packageName}.permission.HOTSEAT_EDU">
+ <intent-filter>
+ <action android:name="com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU"/>
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
</application>
diff --git a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml b/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
index b9621e4..36c9b00 100644
--- a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
+++ b/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
@@ -72,33 +72,42 @@
android:layout_height="0dp"
launcher:containerType="hotseat" />
- <FrameLayout
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
android:paddingTop="8dp"
android:paddingRight="@dimen/bottom_sheet_edu_padding">
- <Button
- android:id="@+id/turn_predictions_on"
- android:layout_width="wrap_content"
+ <FrameLayout
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_gravity="end"
- android:background="?android:attr/selectableItemBackground"
- android:text="@string/hotseat_edu_accept"
- android:textAlignment="textEnd"
- android:textColor="@android:color/white" />
-
- <Button
- android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight=".4">
+ <Button
+ android:id="@+id/no_thanks"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:text="@string/hotseat_edu_dismiss"
+ android:textColor="@android:color/white"/>
+ </FrameLayout>
+ <FrameLayout
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:id="@+id/no_thanks"
- android:text="@string/hotseat_edu_dismiss"
- android:layout_gravity="start"
- android:background="?android:attr/selectableItemBackground"
- android:textColor="@android:color/white" />
+ android:layout_gravity="center_vertical"
+ android:layout_weight=".6">
+ <Button
+ android:id="@+id/turn_predictions_on"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="end"
+ android:text="@string/hotseat_edu_accept"
+ android:textColor="@android:color/white"/>
+ </FrameLayout>
- </FrameLayout>
+ </LinearLayout>
</LinearLayout>
</LinearLayout>
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java
index 0113570..5e54cd2 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java
@@ -16,9 +16,11 @@
package com.android.launcher3.appprediction;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALL_APPS_RANKED;
import android.app.prediction.AppPredictor;
import android.app.prediction.AppTarget;
@@ -26,6 +28,7 @@
import android.content.Context;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener;
@@ -38,8 +41,6 @@
import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener;
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
-import com.android.launcher3.logger.LauncherAtom;
-import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -51,6 +52,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Optional;
import java.util.OptionalInt;
import java.util.stream.IntStream;
@@ -306,40 +308,25 @@
}
/**
- * Logs ranking info for launched app within all apps prediction.
+ * Returns ranking info for the app within all apps prediction.
* Only applicable when {@link ItemInfo#itemType} is one of the followings:
* {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
* {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT},
* {@link LauncherSettings.Favorites#ITEM_TYPE_DEEP_SHORTCUT}
*/
- public void logLaunchedAppRankingInfo(@NonNull ItemInfo itemInfo, InstanceId instanceId) {
- if (itemInfo.getTargetComponent() == null || itemInfo.user == null
- || (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
- && itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
- && itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)) {
- return;
- }
+ public OptionalInt getAllAppsRank(@Nullable ItemInfo itemInfo) {
+ Optional<ComponentKey> componentKey = Optional.ofNullable(itemInfo)
+ .filter(item -> item.itemType == ITEM_TYPE_APPLICATION
+ || item.itemType == ITEM_TYPE_SHORTCUT
+ || item.itemType == ITEM_TYPE_DEEP_SHORTCUT)
+ .map(ItemInfo::getTargetComponent)
+ .map(componentName -> new ComponentKey(componentName, itemInfo.user));
- Launcher launcher = Launcher.getLauncher(mAppsView.getContext());
- final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user);
- final List<ComponentKeyMapper> predictedApps = getCurrentState().apps;
- OptionalInt rank = IntStream.range(0, predictedApps.size())
- .filter((i) -> k.equals(predictedApps.get(i).getComponentKey()))
- .findFirst();
- if (!rank.isPresent()) {
- return;
- }
-
- LauncherAtom.ItemInfo.Builder atomBuilder = LauncherAtom.ItemInfo.newBuilder();
- atomBuilder.setRank(rank.getAsInt());
- atomBuilder.setContainerInfo(
- LauncherAtom.ContainerInfo.newBuilder().setPredictionContainer(
- LauncherAtom.PredictionContainer.newBuilder().build()).build());
- launcher.getStatsLogManager().log(LAUNCHER_ALL_APPS_RANKED, instanceId,
- atomBuilder.build());
+ return componentKey.map(key -> IntStream.range(0, getCurrentState().apps.size())
+ .filter(index -> key.equals(getCurrentState().apps.get(index).getComponentKey()))
+ .findFirst()).orElseGet(OptionalInt::empty);
}
-
/**
* Fill in predicted_rank field based on app prediction.
* Only applicable when {@link ItemInfo#itemType} is one of the followings:
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java
new file mode 100644
index 0000000..c968de9
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 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.hybridhotseat;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.ActivityTracker;
+
+/**
+ * Proxy activity to return user to home screen and show halfsheet education
+ */
+public class HotseatEduActivity extends Activity {
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setPackage(getPackageName())
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ new HotseatActivityTracker<>().addToIntent(homeIntent);
+ startActivity(homeIntent);
+ finish();
+ }
+
+ static class HotseatActivityTracker<T extends QuickstepLauncher> implements
+ ActivityTracker.SchedulerCallback {
+
+ @Override
+ public boolean init(BaseActivity activity, boolean alreadyOnHome) {
+ QuickstepLauncher launcher = (QuickstepLauncher) activity;
+ if (launcher != null && launcher.getHotseatPredictionController() != null) {
+ launcher.getHotseatPredictionController().showEdu();
+ }
+ return false;
+ }
+
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
index 522a2dc..c1bf2fd 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
@@ -84,7 +84,7 @@
}
Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_enabled,
R.string.hotseat_prediction_settings, null,
- () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION)));
+ () -> mLauncher.startActivity(getSettingsIntent()));
}
/**
@@ -237,7 +237,7 @@
< mLauncher.getDeviceProfile().inv.numHotseatIcons) {
Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled,
R.string.hotseat_prediction_settings, null,
- () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION)));
+ () -> mLauncher.startActivity(getSettingsIntent()));
} else {
new ArrowTipView(mLauncher).show(
mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop());
@@ -281,5 +281,9 @@
mActiveDialog.setHotseatEduController(this);
mActiveDialog.show(mPredictedApps);
}
+
+ static Intent getSettingsIntent() {
+ return new Intent(SETTINGS_ACTION).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 30a34e4..7334d80 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -17,7 +17,8 @@
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.hybridhotseat.HotseatEduController.SETTINGS_ACTION;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.hybridhotseat.HotseatEduController.getSettingsIntent;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_RANKED;
import android.animation.Animator;
@@ -29,9 +30,9 @@
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
import android.content.ComponentName;
-import android.content.Intent;
import android.os.Process;
import android.util.Log;
+import android.view.HapticFeedbackConstants;
import android.view.View;
import android.view.ViewGroup;
@@ -54,7 +55,8 @@
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
+import com.android.launcher3.logger.LauncherAtom.PredictedHotseatContainer;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
@@ -69,6 +71,7 @@
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.Snackbar;
@@ -120,9 +123,18 @@
private final View.OnLongClickListener mPredictionLongClickListener = v -> {
if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
if (mLauncher.getWorkspace().isSwitchingState()) return false;
+ if (!mLauncher.getOnboardingPrefs().getBoolean(
+ OnboardingPrefs.HOTSEAT_LONGPRESS_TIP_SEEN)) {
+ Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled,
+ R.string.hotseat_prediction_settings, null,
+ () -> mLauncher.startActivity(getSettingsIntent()));
+ mLauncher.getOnboardingPrefs().markChecked(OnboardingPrefs.HOTSEAT_LONGPRESS_TIP_SEEN);
+ mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ return true;
+ }
// Start the drag
mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions());
- return false;
+ return true;
};
public HotseatPredictionController(Launcher launcher) {
@@ -154,36 +166,35 @@
* Shows appropriate hotseat education based on prediction enabled and migration states.
*/
public void showEdu() {
- if (mComponentKeyMappers.isEmpty()) {
- // launcher has empty predictions set
- Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_disabled,
- R.string.hotseat_prediction_settings, null,
- () -> mLauncher.startActivity(
- new Intent(SETTINGS_ACTION)));
- } else if (isEduSeen()) {
- // user has already went through education
- new ArrowTipView(mLauncher).show(
- mLauncher.getString(R.string.hotsaet_tip_prediction_enabled),
- mHotseat.getTop());
- } else {
- HotseatEduController eduController = new HotseatEduController(mLauncher, mRestoreHelper,
- this::createPredictor);
- eduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers));
- eduController.showEdu();
- }
+ mLauncher.getStateManager().goToState(NORMAL, true, () -> {
+ if (mComponentKeyMappers.isEmpty()) {
+ // launcher has empty predictions set
+ Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_disabled,
+ R.string.hotseat_prediction_settings, null,
+ () -> mLauncher.startActivity(getSettingsIntent()));
+ } else if (isEduSeen() || getPredictedIcons().size() >= (mHotSeatItemsCount + 1) / 2) {
+ showDiscoveryTip();
+ } else {
+ HotseatEduController eduController = new HotseatEduController(mLauncher,
+ mRestoreHelper,
+ this::createPredictor);
+ eduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers));
+ eduController.showEdu();
+ }
+ });
}
/**
* Shows educational tip for hotseat if user does not go through Tips app.
*/
- public void showDiscoveryTip() {
- if (getPredictedIcons().size() == mHotSeatItemsCount) {
+ private void showDiscoveryTip() {
+ if (getPredictedIcons().isEmpty()) {
new ArrowTipView(mLauncher).show(
mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop());
} else {
Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled,
R.string.hotseat_prediction_settings, null,
- () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION)));
+ () -> mLauncher.startActivity(getSettingsIntent()));
}
}
@@ -661,24 +672,25 @@
if (!rank.isPresent()) {
return;
}
- LauncherAtom.PredictedHotseatContainer.Builder containerBuilder =
- LauncherAtom.PredictedHotseatContainer.newBuilder();
- LauncherAtom.ItemInfo.Builder atomBuilder = LauncherAtom.ItemInfo.newBuilder();
+
int cardinality = 0;
for (PredictedAppIcon icon : getPredictedIcons()) {
ItemInfo info = (ItemInfo) icon.getTag();
cardinality |= 1 << info.screenId;
}
+
+ PredictedHotseatContainer.Builder containerBuilder = PredictedHotseatContainer.newBuilder();
containerBuilder.setCardinality(cardinality);
- atomBuilder.setRank(rank.getAsInt());
if (itemInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
containerBuilder.setIndex(rank.getAsInt());
}
- atomBuilder.setContainerInfo(
- LauncherAtom.ContainerInfo.newBuilder().setPredictedHotseatContainer(
- containerBuilder).build());
- mLauncher.getStatsLogManager().log(LAUNCHER_HOTSEAT_RANKED, instanceId,
- atomBuilder.build());
+ mLauncher.getStatsLogManager().logger()
+ .withInstanceId(instanceId)
+ .withRank(rank.getAsInt())
+ .withContainerInfo(ContainerInfo.newBuilder()
+ .setPredictedHotseatContainer(containerBuilder)
+ .build())
+ .log(LAUNCHER_HOTSEAT_RANKED);
}
private class PinPrediction extends SystemShortcut<QuickstepLauncher> {
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 0e690eb..7d86cea 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.QUICK_SWITCH_STATE_ORDINAL;
@@ -45,9 +46,9 @@
import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.Folder;
-import com.android.launcher3.hybridhotseat.HotseatEduController;
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -80,6 +81,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.OptionalInt;
import java.util.stream.Stream;
public class QuickstepLauncher extends BaseQuickstepLauncher {
@@ -108,26 +110,16 @@
}
@Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- if (HotseatEduController.HOTSEAT_EDU_ACTION.equals(intent.getAction())
- && mHotseatPredictionController != null) {
- boolean alreadyOnHome = hasWindowFocus() && ((intent.getFlags()
- & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
- != Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
- getStateManager().goToState(NORMAL, alreadyOnHome, () -> {
- mHotseatPredictionController.showEdu();
- });
- }
- }
-
- @Override
protected void logAppLaunch(ItemInfo info, InstanceId instanceId) {
- super.logAppLaunch(info, instanceId);
+ StatsLogger logger = getStatsLogManager()
+ .logger().withItemInfo(info).withInstanceId(instanceId);
+ OptionalInt allAppsRank = PredictionUiStateManager.INSTANCE.get(this).getAllAppsRank(info);
+ allAppsRank.ifPresent(logger::withRank);
+ logger.log(LAUNCHER_APP_LAUNCH_TAP);
+
if (mHotseatPredictionController != null) {
mHotseatPredictionController.logLaunchedAppRankingInfo(info, instanceId);
}
- PredictionUiStateManager.INSTANCE.get(this).logLaunchedAppRankingInfo(info, instanceId);
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index ba8656d..a0af797 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -24,6 +24,7 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
+import static com.android.launcher3.WorkspaceStateTransitionAnimation.getSpringScaleAnimator;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
@@ -90,6 +91,10 @@
protected static final int NEXT_INDEX = RecentsAtomicAnimationFactory.NEXT_INDEX
+ MY_ANIM_COUNT;
+ // Due to use of physics, duration may differ between devices so we need to calculate and
+ // cache the value.
+ private int mHintToNormalDuration = -1;
+
public static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300;
public QuickstepAtomicAnimationFactory(QuickstepLauncher activity) {
@@ -221,6 +226,14 @@
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator);
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, translationInterpolator);
config.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
+ } else if (fromState == HINT_STATE && toState == NORMAL) {
+ config.setInterpolator(ANIM_DEPTH, DEACCEL_3);
+ if (mHintToNormalDuration == -1) {
+ ValueAnimator va = getSpringScaleAnimator(mActivity, mActivity.getWorkspace(),
+ toState.getWorkspaceScaleAndTranslation(mActivity).scale);
+ mHintToNormalDuration = (int) va.getDuration();
+ }
+ config.duration = Math.max(config.duration, mHintToNormalDuration);
}
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 39bbfb9..a35e13a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -15,10 +15,13 @@
*/
package com.android.launcher3.uioverrides.touchcontrollers;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_EDU;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.touch.AbstractStateChangeTouchController.SUCCESS_TRANSITION_PROGRESS;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
@@ -112,7 +115,8 @@
}
return true;
}
- if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ int typeToClose = ENABLE_ALL_APPS_EDU.get() ? TYPE_ALL & ~TYPE_ALL_APPS_EDU : TYPE_ALL;
+ if (AbstractFloatingView.getTopOpenViewWithType(mLauncher, typeToClose) != null) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED,
"NavBarToHomeTouchController.canInterceptTouch true 2 "
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 4cc8256..9316938 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -26,6 +26,7 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.graphics.PointF;
import android.util.Log;
@@ -35,6 +36,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.graphics.OverviewScrim;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.testing.TestProtocol;
@@ -65,6 +67,9 @@
// The last recorded displacement before we reached overview.
private PointF mStartDisplacement = new PointF();
+ // Normal to Hint animation has flag SKIP_OVERVIEW, so we update this scrim with this animator.
+ private ObjectAnimator mNormalToHintOverviewScrimAnimator;
+
public NoButtonNavbarToOverviewTouchController(Launcher l) {
super(l);
mRecentsView = l.getOverviewPanel();
@@ -110,11 +115,31 @@
@Override
public void onDragStart(boolean start, float startDisplacement) {
super.onDragStart(start, startDisplacement);
-
+ if (mFromState == NORMAL && mToState == HINT_STATE) {
+ mNormalToHintOverviewScrimAnimator = ObjectAnimator.ofFloat(
+ mLauncher.getDragLayer().getOverviewScrim(),
+ OverviewScrim.SCRIM_PROGRESS,
+ mFromState.getOverviewScrimAlpha(mLauncher),
+ mToState.getOverviewScrimAlpha(mLauncher));
+ }
mReachedOverview = false;
}
@Override
+ protected void updateProgress(float fraction) {
+ super.updateProgress(fraction);
+ if (mNormalToHintOverviewScrimAnimator != null) {
+ mNormalToHintOverviewScrimAnimator.setCurrentFraction(fraction);
+ }
+ }
+
+ @Override
+ public void onDragEnd(float velocity) {
+ super.onDragEnd(velocity);
+ mNormalToHintOverviewScrimAnimator = null;
+ }
+
+ @Override
protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration,
LauncherState targetState, float velocity, boolean isFling) {
super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState, velocity,
@@ -132,6 +157,7 @@
if (mCurrentAnimation == null) {
return;
}
+ mNormalToHintOverviewScrimAnimator = null;
mCurrentAnimation.dispatchOnCancelWithoutCancelRunnable(() -> {
mLauncher.getStateManager().goToState(OVERVIEW, true, () -> {
mReachedOverview = true;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index f5c5874..9db6576 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -121,6 +121,10 @@
});
mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
+ // Wait until the first scroll event before applying scroll to taskViewSimulator.
+ // Since, by default the current/running task already centered, this ensures that we
+ // do not move the running task, in case RecentsView has not yet laid out completely.
+ mRecentsViewScrollLinked = true;
if (moveWindowWithRecentsScroll()) {
updateFinalShift();
}
@@ -128,7 +132,6 @@
runOnRecentsAnimationStart(() ->
mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController,
mRecentsAnimationTargets));
- mRecentsViewScrollLinked = true;
}
protected void startNewTask(Consumer<Boolean> resultCallback) {
@@ -205,26 +208,30 @@
mRecentsAnimationController = recentsAnimationController;
mRecentsAnimationTargets = targets;
mTransformParams.setTargetSet(mRecentsAnimationTargets);
- DeviceProfile dp = mTaskViewSimulator.getOrientationState().getLauncherDeviceProfile();
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(
mGestureState.getRunningTaskId());
- if (targets.minimizedHomeBounds != null && runningTaskTarget != null) {
- Rect overviewStackBounds = mActivityInterface
- .getOverviewWindowBounds(targets.minimizedHomeBounds, runningTaskTarget);
- dp = dp.getMultiWindowProfile(mContext,
- new WindowBounds(overviewStackBounds, targets.homeContentInsets));
- } else {
- // If we are not in multi-window mode, home insets should be same as system insets.
- dp = dp.copy(mContext);
- }
- dp.updateInsets(targets.homeContentInsets);
- dp.updateIsSeascape(mContext);
if (runningTaskTarget != null) {
mTaskViewSimulator.setPreview(runningTaskTarget);
}
- initTransitionEndpoints(dp);
+ // Only initialize the device profile, if it has not been initialized before, as in some
+ // configurations targets.homeContentInsets may not be correct.
+ if (mActivity == null) {
+ DeviceProfile dp = mTaskViewSimulator.getOrientationState().getLauncherDeviceProfile();
+ if (targets.minimizedHomeBounds != null && runningTaskTarget != null) {
+ Rect overviewStackBounds = mActivityInterface
+ .getOverviewWindowBounds(targets.minimizedHomeBounds, runningTaskTarget);
+ dp = dp.getMultiWindowProfile(mContext,
+ new WindowBounds(overviewStackBounds, targets.homeContentInsets));
+ } else {
+ // If we are not in multi-window mode, home insets should be same as system insets.
+ dp = dp.copy(mContext);
+ }
+ dp.updateInsets(targets.homeContentInsets);
+ dp.updateIsSeascape(mContext);
+ initTransitionEndpoints(dp);
+ }
// Notify when the animation starts
if (!mRecentsAnimationStartCallbacks.isEmpty()) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/ImageActionsApi.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/ImageActionsApi.java
index e49c466..ba8ba33 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/ImageActionsApi.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/ImageActionsApi.java
@@ -17,6 +17,7 @@
package com.android.quickstep;
import static android.content.Intent.EXTRA_STREAM;
+import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.util.ImageActionUtils.persistBitmapAndStartActivity;
@@ -67,7 +68,9 @@
UI_HELPER_EXECUTOR.execute(() -> persistBitmapAndStartActivity(mContext,
mBitmapSupplier.get(), crop, intent, (uri, intentForUri) -> {
- intentForUri.putExtra(EXTRA_STREAM, uri);
+ intentForUri
+ .addFlags(FLAG_GRANT_READ_URI_PERMISSION)
+ .putExtra(EXTRA_STREAM, uri);
return new Intent[]{intentForUri};
}, TAG));
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
index ebc83c6..6f4d34c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -4,21 +4,18 @@
import android.content.Context;
import android.os.Bundle;
+import com.android.launcher3.LauncherState;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.testing.TestInformationHandler;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
import com.android.quickstep.util.LayoutUtils;
-import com.android.systemui.shared.recents.model.Task;
-
-import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
public class QuickstepTestInformationHandler extends TestInformationHandler {
- private final Context mContext;
+ protected final Context mContext;
+
public QuickstepTestInformationHandler(Context context) {
mContext = context;
}
@@ -27,6 +24,15 @@
public Bundle call(String method) {
final Bundle response = new Bundle();
switch (method) {
+ case TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT: {
+ return getLauncherUIProperty(Bundle::putInt, l -> {
+ final float progress = LauncherState.OVERVIEW.getVerticalProgress(l)
+ - LauncherState.ALL_APPS.getVerticalProgress(l);
+ final float distance = l.getAllAppsController().getShiftRange() * progress;
+ return (int) distance;
+ });
+ }
+
case TestProtocol.REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT: {
final float swipeHeight =
LayoutUtils.getDefaultSwipeHeight(mContext, mDeviceProfile);
@@ -47,26 +53,6 @@
Bundle::putInt, PortraitStatesTouchController::getHotseatTop);
}
- case TestProtocol.REQUEST_RECENT_TASKS_LIST: {
- ArrayList<String> taskBaseIntentComponents = new ArrayList<>();
- CountDownLatch latch = new CountDownLatch(1);
- RecentsModel.INSTANCE.get(mContext).getTasks((tasks) -> {
- for (Task t : tasks) {
- taskBaseIntentComponents.add(
- t.key.baseIntent.getComponent().flattenToString());
- }
- latch.countDown();
- });
- try {
- latch.await(2, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- response.putStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD,
- taskBaseIntentComponents);
- return response;
- }
-
case TestProtocol.REQUEST_OVERVIEW_ACTIONS_ENABLED: {
response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get());
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
index 196a7c4..32da52e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -141,7 +141,8 @@
*/
public void setPreview(RemoteAnimationTargetCompat runningTarget) {
setPreviewBounds(runningTarget.screenSpaceBounds, runningTarget.contentInsets);
- mRunningTargetWindowPosition.set(runningTarget.position.x, runningTarget.position.y);
+ mRunningTargetWindowPosition.set(runningTarget.screenSpaceBounds.left,
+ runningTarget.screenSpaceBounds.top);
}
/**
@@ -255,8 +256,8 @@
float taskHeight = mTaskRect.height();
mMatrix.set(mPositionHelper.getMatrix());
- mMatrix.postScale(scale, scale);
mMatrix.postTranslate(insets.left, insets.top);
+ mMatrix.postScale(scale, scale);
// Apply TaskView matrix: translate, scale, scroll
mMatrix.postTranslate(mTaskRect.left, mTaskRect.top);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 99afe39..6380bbe 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -798,8 +798,10 @@
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
TaskView taskView = getTaskViewAt(i);
if (mIgnoreResetTaskId != taskView.getTask().key.id) {
- taskView.resetVisualProperties();
+ taskView.resetViewTransforms();
taskView.setStableAlpha(mContentAlpha);
+ taskView.setFullscreenProgress(mFullscreenProgress);
+ taskView.setModalness(mTaskModalness);
}
}
if (mRunningTaskTileHidden) {
@@ -998,6 +1000,7 @@
mDwbToastShown = false;
mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
LayoutUtils.setViewEnabled(mActionsView, true);
+ mOrientationState.setGestureActive(false);
}
public @Nullable TaskView getRunningTaskView() {
@@ -1035,6 +1038,7 @@
*/
public void onGestureAnimationStart(int runningTaskId) {
// This needs to be called before the other states are set since it can create the task view
+ mOrientationState.setGestureActive(true);
showCurrentTask(runningTaskId);
setEnableFreeScroll(false);
setEnableDrawingLiveTile(false);
@@ -1097,6 +1101,8 @@
* Called when a gesture from an app has finished.
*/
public void onGestureAnimationEnd() {
+ mOrientationState.setGestureActive(false);
+
setOnScrollChangeListener(null);
setEnableFreeScroll(true);
setEnableDrawingLiveTile(true);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 411bab4..82fabac 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -545,7 +545,7 @@
setIconAndDimTransitionProgress(iconScale, invert);
}
- private void resetViewTransforms() {
+ protected void resetViewTransforms() {
setCurveScale(1);
setTranslationX(0f);
setTranslationY(0f);
@@ -554,12 +554,6 @@
setIconScaleAndDim(1);
}
- public void resetVisualProperties() {
- resetViewTransforms();
- setFullscreenProgress(0);
- setModalness(0);
- }
-
public void setStableAlpha(float parentAlpha) {
mStableAlpha = parentAlpha;
setAlpha(mStableAlpha);
@@ -953,9 +947,6 @@
*/
public void setFullscreenProgress(float progress) {
progress = Utilities.boundToRange(progress, 0, 1);
- if (progress == mFullscreenProgress) {
- return;
- }
mFullscreenProgress = progress;
boolean isFullscreen = mFullscreenProgress > 0;
mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 1b82826..769d298 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -87,7 +87,7 @@
<string name="hotseat_tip_gaps_filled">App suggestions added to empty space</string>
<!-- tip shown when user migrates and predictions are enabled in hotseat -->
<string name="hotsaet_tip_prediction_enabled">App suggestions enabled</string>
- <!-- tip shown when hotseat edu is requested while predicions are disabled -->
+ <!-- tip shown when hotseat edu is requested while predictions are disabled -->
<string name="hotsaet_tip_prediction_disabled">App suggestions are disabled</string>
<!-- content description for hotseat items -->
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
new file mode 100644
index 0000000..a31ba21
--- /dev/null
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2020 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.util;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.hardware.display.DisplayManager;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.shadows.LShadowDisplay;
+import com.android.launcher3.util.DefaultDisplay;
+import com.android.quickstep.LauncherActivityInterface;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
+import org.robolectric.annotation.LooperMode.Mode;
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowDisplayManager;
+
+@RunWith(RobolectricTestRunner.class)
+@LooperMode(Mode.PAUSED)
+public class TaskViewSimulatorTest {
+
+ @Test
+ public void taskProperlyScaled_portrait_noRotation_sameInsets1() {
+ new TaskMatrixVerifier()
+ .withLauncherSize(1200, 2450)
+ .withInsets(new Rect(0, 80, 0, 120))
+ .verifyNoTransforms();
+ }
+
+ @Test
+ public void taskProperlyScaled_portrait_noRotation_sameInsets2() {
+ new TaskMatrixVerifier()
+ .withLauncherSize(1200, 2450)
+ .withInsets(new Rect(55, 80, 55, 120))
+ .verifyNoTransforms();
+ }
+
+ @Test
+ public void taskProperlyScaled_landscape_noRotation_sameInsets1() {
+ new TaskMatrixVerifier()
+ .withLauncherSize(2450, 1250)
+ .withInsets(new Rect(0, 80, 0, 40))
+ .verifyNoTransforms();
+ }
+
+ @Test
+ public void taskProperlyScaled_landscape_noRotation_sameInsets2() {
+ new TaskMatrixVerifier()
+ .withLauncherSize(2450, 1250)
+ .withInsets(new Rect(0, 80, 120, 0))
+ .verifyNoTransforms();
+ }
+
+ @Test
+ public void taskProperlyScaled_landscape_noRotation_sameInsets3() {
+ new TaskMatrixVerifier()
+ .withLauncherSize(2450, 1250)
+ .withInsets(new Rect(55, 80, 55, 120))
+ .verifyNoTransforms();
+ }
+
+ @Test
+ public void taskProperlyScaled_landscape_rotated() {
+ new TaskMatrixVerifier()
+ .withLauncherSize(1200, 2450)
+ .withInsets(new Rect(0, 80, 0, 120))
+ .withAppBounds(
+ new Rect(0, 0, 2450, 1200),
+ new Rect(0, 80, 0, 120),
+ Surface.ROTATION_90)
+ .verifyNoTransforms();
+ }
+
+ private static class TaskMatrixVerifier extends TransformParams {
+
+ private final Context mContext = RuntimeEnvironment.application;
+
+ private Rect mAppBounds = new Rect();
+ private Rect mLauncherInsets = new Rect();
+
+ private Rect mAppInsets;
+
+ private int mAppRotation = -1;
+ private DeviceProfile mDeviceProfile;
+
+ TaskMatrixVerifier withLauncherSize(int width, int height) {
+ ShadowDisplayManager.changeDisplay(DEFAULT_DISPLAY,
+ String.format("w%sdp-h%sdp-mdpi", width, height));
+ if (mAppBounds.isEmpty()) {
+ mAppBounds.set(0, 0, width, height);
+ }
+ return this;
+ }
+
+ TaskMatrixVerifier withInsets(Rect insets) {
+ LShadowDisplay shadowDisplay = Shadow.extract(
+ mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
+ shadowDisplay.setInsets(insets);
+ mLauncherInsets.set(insets);
+ return this;
+ }
+
+ TaskMatrixVerifier withAppBounds(Rect bounds, Rect insets, int appRotation) {
+ mAppBounds.set(bounds);
+ mAppInsets = insets;
+ mAppRotation = appRotation;
+ return this;
+ }
+
+ void verifyNoTransforms() {
+ mDeviceProfile = InvariantDeviceProfile.INSTANCE.get(mContext)
+ .getDeviceProfile(mContext);
+ mDeviceProfile.updateInsets(mLauncherInsets);
+
+ TaskViewSimulator tvs = new TaskViewSimulator(mContext,
+ LauncherActivityInterface.INSTANCE);
+ tvs.setDp(mDeviceProfile);
+
+ int launcherRotation = DefaultDisplay.INSTANCE.get(mContext).getInfo().rotation;
+ if (mAppRotation < 0) {
+ mAppRotation = launcherRotation;
+ }
+ tvs.setLayoutRotation(launcherRotation, mAppRotation);
+ if (mAppInsets == null) {
+ mAppInsets = new Rect(mLauncherInsets);
+ }
+ tvs.setPreviewBounds(mAppBounds, mAppInsets);
+
+ tvs.fullScreenProgress.value = 1;
+ tvs.recentsViewScale.value = tvs.getFullScreenScale();
+ tvs.apply(this);
+ }
+
+ @Override
+ public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
+ SurfaceParams.Builder builder = new SurfaceParams.Builder((SurfaceControl) null);
+ proxy.onBuildTargetParams(builder, null, this);
+ return new SurfaceParams[] {builder.build()};
+ }
+
+ @Override
+ public void applySurfaceParams(SurfaceParams[] params) {
+ // Verify that the task position remains the same
+ RectF newAppBounds = new RectF(mAppBounds);
+ params[0].matrix.mapRect(newAppBounds);
+ Assert.assertThat(newAppBounds, new AlmostSame(mAppBounds));
+
+ System.err.println("Bounds mapped: " + mAppBounds + " => " + newAppBounds);
+ }
+ }
+
+ private static class AlmostSame extends TypeSafeMatcher<RectF> {
+
+ // Allow 1px error margin to account for float to int conversions
+ private final float mError = 1f;
+ private final Rect mExpected;
+
+ AlmostSame(Rect expected) {
+ mExpected = expected;
+ }
+
+ @Override
+ protected boolean matchesSafely(RectF item) {
+ return Math.abs(item.left - mExpected.left) < mError
+ && Math.abs(item.top - mExpected.top) < mError
+ && Math.abs(item.right - mExpected.right) < mError
+ && Math.abs(item.bottom - mExpected.bottom) < mError;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendValue(mExpected);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 8745814..20ee61d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -16,6 +16,8 @@
package com.android.launcher3.uioverrides.touchcontrollers;
import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
+import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -36,7 +38,6 @@
import android.view.MotionEvent;
import android.view.animation.Interpolator;
-import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
@@ -124,7 +125,7 @@
return false;
}
}
- if (AbstractFloatingView.getTopOpenViewWithType(mLauncher, TYPE_ACCESSIBLE) != null) {
+ if (getTopOpenViewWithType(mLauncher, TYPE_ACCESSIBLE | TYPE_ALL_APPS_EDU) != null) {
return false;
}
return true;
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 54894f0..e496807 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.PREDICTED_HOTSEAT_CONTAINER;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORKSPACE_SNAPSHOT;
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__ALLAPPS;
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__BACKGROUND;
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__HOME;
@@ -32,6 +33,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.Utilities;
import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.logging.StatsLogManager;
@@ -47,6 +49,7 @@
import com.android.systemui.shared.system.SysUiStatsLog;
import java.util.ArrayList;
+import java.util.Optional;
import java.util.OptionalInt;
/**
@@ -80,38 +83,6 @@
}
/**
- * Logs an event.
- *
- * @param event an enum implementing EventEnum interface.
- * @param atomInfo item typically containing app or task launch related information.
- */
- public void log(EventEnum event, InstanceId instanceId, LauncherAtom.ItemInfo atomInfo) {
- LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
- new BaseModelUpdateTask() {
- @Override
- public void execute(LauncherAppState app, BgDataModel dataModel,
- AllAppsList apps) {
- write(event, instanceId, atomInfo, LAUNCHER_UICHANGED__DST_STATE__HOME,
- LAUNCHER_UICHANGED__DST_STATE__BACKGROUND, OptionalInt.empty());
- }
- });
- }
-
- /**
- * Logs an event.
- *
- * @param event an enum implementing EventEnum interface.
- * @param atomItemInfo item typically containing app or task launch related information.
- */
- @Override
- public void log(EventEnum event, @Nullable LauncherAtom.ItemInfo atomItemInfo, int srcState,
- int dstState) {
- write(event, DEFAULT_INSTANCE_ID,
- atomItemInfo == null ? LauncherAtom.ItemInfo.getDefaultInstance() : atomItemInfo,
- srcState, dstState, OptionalInt.empty());
- }
-
- /**
* Logs a ranking event and accompanying {@link InstanceId} and package name.
*/
@Override
@@ -124,49 +95,6 @@
position /* position_picked = 4; */);
}
- private void write(EventEnum event, InstanceId instanceId,
- LauncherAtom.ItemInfo atomInfo,
- int srcState, int dstState, OptionalInt mRank) {
- if (IS_VERBOSE) {
- String name = (event instanceof Enum) ? ((Enum) event).name() :
- event.getId() + "";
-
- Log.d(TAG, instanceId == DEFAULT_INSTANCE_ID
- ? String.format("\n%s (State:%s->%s)\n%s", name, getStateString(srcState),
- getStateString(dstState), atomInfo)
- : String.format("\n%s (State:%s->%s) (InstanceId:%s)\n%s", name,
- getStateString(srcState), getStateString(dstState), instanceId,
- atomInfo));
- }
-
- SysUiStatsLog.write(
- SysUiStatsLog.LAUNCHER_EVENT,
- SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION /* deprecated */,
- srcState,
- dstState,
- null /* launcher extensions, deprecated */,
- false /* quickstep_enabled, deprecated */,
- event.getId() /* event_id */,
- atomInfo.getItemCase().getNumber() /* target_id */,
- instanceId.getId() /* instance_id TODO */,
- 0 /* uid TODO */,
- getPackageName(atomInfo) /* package_name */,
- getComponentName(atomInfo) /* component_name */,
- getGridX(atomInfo, false) /* grid_x */,
- getGridY(atomInfo, false) /* grid_y */,
- getPageId(atomInfo, false) /* page_id */,
- getGridX(atomInfo, true) /* grid_x_parent */,
- getGridY(atomInfo, true) /* grid_y_parent */,
- getPageId(atomInfo, true) /* page_id_parent */,
- getHierarchy(atomInfo) /* hierarchy */,
- atomInfo.getIsWork() /* is_work_profile */,
- mRank.orElse(atomInfo.getRank()) /* rank */,
- atomInfo.getFolderIcon().getFromLabelState().getNumber() /* fromState */,
- atomInfo.getFolderIcon().getToLabelState().getNumber() /* toState */,
- atomInfo.getFolderIcon().getLabelInfo() /* edittext */,
- getCardinality(atomInfo) /* cardinality */);
- }
-
/**
* Logs the workspace layout information on the model thread.
*/
@@ -214,7 +142,7 @@
return;
}
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_SNAPSHOT,
- 0 /* event_id */,
+ LAUNCHER_WORKSPACE_SNAPSHOT.getId() /* event_id */,
info.getItemCase().getNumber() /* target_id */,
instanceId.getId() /* instance_id */,
0 /* uid */,
@@ -237,15 +165,22 @@
/**
* Helps to construct and write statsd compatible log message.
*/
- private class StatsCompatLogger implements StatsLogger {
- private ItemInfo mItemInfo = new ItemInfo();
+ private static class StatsCompatLogger implements StatsLogger {
+
+ private static final ItemInfo DEFAULT_ITEM_INFO = new ItemInfo();
+ private ItemInfo mItemInfo = DEFAULT_ITEM_INFO;
private InstanceId mInstanceId = DEFAULT_INSTANCE_ID;
private OptionalInt mRank = OptionalInt.empty();
+ private Optional<ContainerInfo> mContainerInfo = Optional.empty();
private int mSrcState = LAUNCHER_UICHANGED__SRC_STATE__HOME;
private int mDstState = LAUNCHER_UICHANGED__DST_STATE__BACKGROUND;
@Override
public StatsLogger withItemInfo(ItemInfo itemInfo) {
+ if (mContainerInfo.isPresent()) {
+ throw new IllegalArgumentException(
+ "ItemInfo and ContainerInfo are mutual exclusive; cannot log both.");
+ }
this.mItemInfo = itemInfo;
return this;
}
@@ -275,14 +210,35 @@
}
@Override
+ public StatsLogger withContainerInfo(ContainerInfo containerInfo) {
+ if (mItemInfo != DEFAULT_ITEM_INFO) {
+ throw new IllegalArgumentException(
+ "ItemInfo and ContainerInfo are mutual exclusive; cannot log both.");
+ }
+ this.mContainerInfo = Optional.of(containerInfo);
+ return this;
+ }
+
+ @Override
public void log(EventEnum event) {
if (!Utilities.ATLEAST_R) {
return;
}
+ LauncherAtom.ItemInfo.Builder itemInfoBuilder =
+ (LauncherAtom.ItemInfo.Builder) mItemInfo.buildProto().toBuilder();
+ mRank.ifPresent(itemInfoBuilder::setRank);
+ if (mContainerInfo.isPresent()) {
+ // User already provided container info;
+ // default container info from item info will be ignored.
+ itemInfoBuilder.setContainerInfo(mContainerInfo.get());
+ write(event, mInstanceId, itemInfoBuilder.build(), mSrcState, mDstState);
+ return;
+ }
+
if (mItemInfo.container < 0) {
// Item is not within a folder. Write to StatsLog in same thread.
- write(event, mInstanceId, mItemInfo.buildProto(), mSrcState, mDstState, mRank);
+ write(event, mInstanceId, itemInfoBuilder.build(), mSrcState, mDstState);
} else {
// Item is inside the folder, fetch folder info in a BG thread
// and then write to StatsLog.
@@ -292,12 +248,58 @@
public void execute(LauncherAppState app, BgDataModel dataModel,
AllAppsList apps) {
FolderInfo folderInfo = dataModel.folders.get(mItemInfo.container);
- write(event, mInstanceId, mItemInfo.buildProto(folderInfo),
- mSrcState, mDstState, mRank);
+ LauncherAtom.ItemInfo.Builder atomInfoBuilder =
+ (LauncherAtom.ItemInfo.Builder) mItemInfo
+ .buildProto(folderInfo).toBuilder();
+ mRank.ifPresent(atomInfoBuilder::setRank);
+ write(event, mInstanceId, atomInfoBuilder.build(), mSrcState,
+ mDstState);
}
});
}
}
+
+ private void write(EventEnum event, InstanceId instanceId, LauncherAtom.ItemInfo atomInfo,
+ int srcState, int dstState) {
+ if (IS_VERBOSE) {
+ String name = (event instanceof Enum) ? ((Enum) event).name() :
+ event.getId() + "";
+
+ Log.d(TAG, instanceId == DEFAULT_INSTANCE_ID
+ ? String.format("\n%s (State:%s->%s)\n%s", name, getStateString(srcState),
+ getStateString(dstState), atomInfo)
+ : String.format("\n%s (State:%s->%s) (InstanceId:%s)\n%s", name,
+ getStateString(srcState), getStateString(dstState), instanceId,
+ atomInfo));
+ }
+
+ SysUiStatsLog.write(
+ SysUiStatsLog.LAUNCHER_EVENT,
+ SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION /* deprecated */,
+ srcState,
+ dstState,
+ null /* launcher extensions, deprecated */,
+ false /* quickstep_enabled, deprecated */,
+ event.getId() /* event_id */,
+ atomInfo.getItemCase().getNumber() /* target_id */,
+ instanceId.getId() /* instance_id TODO */,
+ 0 /* uid TODO */,
+ getPackageName(atomInfo) /* package_name */,
+ getComponentName(atomInfo) /* component_name */,
+ getGridX(atomInfo, false) /* grid_x */,
+ getGridY(atomInfo, false) /* grid_y */,
+ getPageId(atomInfo, false) /* page_id */,
+ getGridX(atomInfo, true) /* grid_x_parent */,
+ getGridY(atomInfo, true) /* grid_y_parent */,
+ getPageId(atomInfo, true) /* page_id_parent */,
+ getHierarchy(atomInfo) /* hierarchy */,
+ atomInfo.getIsWork() /* is_work_profile */,
+ atomInfo.getRank() /* rank */,
+ atomInfo.getFolderIcon().getFromLabelState().getNumber() /* fromState */,
+ atomInfo.getFolderIcon().getToLabelState().getNumber() /* toState */,
+ atomInfo.getFolderIcon().getLabelInfo() /* edittext */,
+ getCardinality(atomInfo) /* cardinality */);
+ }
}
private static int getCardinality(LauncherAtom.ItemInfo info) {
diff --git a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
index 0b48a8b..f302fdd 100644
--- a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
+++ b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
@@ -88,8 +88,14 @@
@WorkerThread
public static void persistBitmapAndStartActivity(Context context, Bitmap bitmap, Rect crop,
Intent intent, BiFunction<Uri, Intent, Intent[]> uriToIntentMap, String tag) {
- context.startActivities(
- uriToIntentMap.apply(getImageUri(bitmap, crop, context, tag), intent));
+ Intent[] intents = uriToIntentMap.apply(getImageUri(bitmap, crop, context, tag), intent);
+
+ // Work around b/159412574
+ if (intents.length == 1) {
+ context.startActivity(intents[0]);
+ } else {
+ context.startActivities(intents);
+ }
}
/**
@@ -158,13 +164,13 @@
intent = new Intent();
}
ClipData clipdata = new ClipData(new ClipDescription("content",
- new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}),
+ new String[]{"image/png"}),
new ClipData.Item(uri));
intent.setAction(Intent.ACTION_SEND)
.setComponent(null)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .addFlags(FLAG_GRANT_READ_URI_PERMISSION)
.setType("image/png")
- .setFlags(FLAG_GRANT_READ_URI_PERMISSION)
.putExtra(Intent.EXTRA_STREAM, uri)
.setClipData(clipdata);
return new Intent[]{Intent.createChooser(intent, null).addFlags(FLAG_ACTIVITY_NEW_TASK)};
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index 1abe903..0fdc684 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -115,7 +115,7 @@
HotseatPredictionController client = mLauncher.getHotseatPredictionController();
if (mFromAllApps && finalState == NORMAL && client.hasPredictions()) {
if (incrementEventCount(HOTSEAT_DISCOVERY_TIP_COUNT)) {
- client.showDiscoveryTip();
+ client.showEdu();
stateManager.removeStateListener(this);
}
}
@@ -144,7 +144,7 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState == NORMAL) {
- if (mCount == MAX_NUM_SWIPES_TO_TRIGGER_EDU) {
+ if (mCount >= MAX_NUM_SWIPES_TO_TRIGGER_EDU) {
if (getOpenView(mLauncher, TYPE_ALL_APPS_EDU) == null) {
AllAppsEduView.show(launcher);
}
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index 68636cb..90ee18f 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -105,6 +105,9 @@
private static final int FLAG_ROTATION_WATCHER_ENABLED = 1 << 6;
// Enable home rotation for UI tests, ignoring home rotation value from prefs
private static final int FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING = 1 << 7;
+ // Whether the swipe gesture is running, so the recents would stay locked in the
+ // current orientation
+ private static final int FLAG_SWIPE_UP_NOT_RUNNING = 1 << 8;
private static final int MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE =
FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY
@@ -114,7 +117,8 @@
// multi-window is enabled as in that case, activity itself rotates.
private static final int VALUE_ROTATION_WATCHER_ENABLED =
MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE | FLAG_SYSTEM_ROTATION_ALLOWED
- | FLAG_ROTATION_WATCHER_SUPPORTED | FLAG_ROTATION_WATCHER_ENABLED;
+ | FLAG_ROTATION_WATCHER_SUPPORTED | FLAG_ROTATION_WATCHER_ENABLED
+ | FLAG_SWIPE_UP_NOT_RUNNING;
private final Context mContext;
private final ContentResolver mContentResolver;
@@ -156,6 +160,7 @@
if (originalSmallestWidth < 600) {
mFlags |= FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY;
}
+ mFlags |= FLAG_SWIPE_UP_NOT_RUNNING;
initFlags();
}
@@ -167,6 +172,13 @@
}
/**
+ * Sets if the swipe up gesture is currently running or not
+ */
+ public void setGestureActive(boolean isGestureActive) {
+ setFlag(FLAG_SWIPE_UP_NOT_RUNNING, !isGestureActive);
+ }
+
+ /**
* Sets the appropriate {@link PagedOrientationHandler} for {@link #mOrientationHandler}
* @param touchRotation The rotation the nav bar region that is touched is in
* @param displayRotation Rotation of the display/device
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index 4b7097a..881df1b 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -22,7 +22,7 @@
android:theme="@style/PopupItem" >
<com.android.launcher3.BubbleTextView
- style="@style/BaseIcon"
+ style="@style/BaseIconUnBounded"
android:id="@+id/bubble_text"
android:background="?android:attr/selectableItemBackground"
android:gravity="start|center_vertical"
@@ -30,6 +30,7 @@
android:paddingStart="@dimen/deep_shortcuts_text_padding_start"
android:paddingEnd="@dimen/popup_padding_end"
android:textSize="14sp"
+ android:maxLines="2"
android:textColor="?android:attr/textColorPrimary"
launcher:iconDisplay="shortcut_popup"
launcher:layoutHorizontal="true"
diff --git a/res/values/config.xml b/res/values/config.xml
index 4cbc597..ca25325 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -144,6 +144,10 @@
<item name="staggered_stiffness" type="dimen" format="float">150</item>
<dimen name="unlock_staggered_velocity_dp_per_s">3dp</dimen>
+ <item name="hint_scale_damping_ratio" type="dimen" format="float">0.7</item>
+ <item name="hint_scale_stiffness" type="dimen" format="float">200</item>
+ <dimen name="hint_scale_velocity_dp_per_s">0.3dp</dimen>
+
<!-- Swipe up to home related -->
<dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
<dimen name="swipe_up_y_overshoot">10dp</dimen>
@@ -175,6 +179,10 @@
<item>@dimen/swipe_up_fling_min_visible_change</item>
<item>@dimen/swipe_up_y_overshoot</item>
+
+ <item>@dimen/hint_scale_damping_ratio</item>
+ <item>@dimen/hint_scale_stiffness</item>
+ <item>@dimen/hint_scale_velocity_dp_per_s</item>
</array>
<string-array name="live_wallpapers_remove_sysui_scrims">
diff --git a/res/values/styles.xml b/res/values/styles.xml
index ac00488..82f5dc6 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -55,7 +55,7 @@
<item name="iconOnlyShortcutColor">?android:attr/textColorSecondary</item>
<item name="workProfileOverlayTextColor">#FF212121</item>
<item name="eduHalfSheetBGColor">?android:attr/colorAccent</item>
- <item name="disabledIconAlpha">.36</item>
+ <item name="disabledIconAlpha">.54</item>
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">false</item>
@@ -69,7 +69,7 @@
<style name="LauncherTheme.DarkMainColor" parent="@style/LauncherTheme">
<item name="folderFillColor">#FF3C4043</item> <!-- 100% GM2 800 -->
<item name="folderTextColor">?attr/workspaceTextColor</item>
- <item name="disabledIconAlpha">.24</item>
+ <item name="disabledIconAlpha">.254</item>
</style>
@@ -117,7 +117,7 @@
<style name="LauncherTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark">
<item name="folderFillColor">#FF3C4043</item> <!-- 100% GM2 800 -->
<item name="folderTextColor">@android:color/white</item>
- <item name="disabledIconAlpha">.24</item>
+ <item name="disabledIconAlpha">.54</item>
</style>
<style name="LauncherTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark">
@@ -187,28 +187,31 @@
</style>
<style name="AllAppsTheme">
- <item name="disabledIconAlpha">.24</item>
+ <item name="disabledIconAlpha">.54</item>
</style>
<style name="AllAppsTheme.Dark">
- <item name="disabledIconAlpha">.28</item>
+ <item name="disabledIconAlpha">.54</item>
</style>
- <!-- Base theme for BubbleTextView and sub classes -->
- <style name="BaseIcon" parent="@android:style/TextAppearance.DeviceDefault">
+
+ <style name="BaseIconUnBounded" parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_gravity">center</item>
<item name="android:focusable">true</item>
<item name="android:gravity">center_horizontal</item>
- <item name="android:lines">1</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:defaultFocusHighlightEnabled">false</item>
-
<!-- No shadows in the base theme -->
<item name="android:shadowRadius">0</item>
</style>
+ <!-- Base theme for BubbleTextView and sub classes -->
+ <style name="BaseIcon" parent="BaseIconUnBounded">
+ <item name="android:lines">1</item>
+ </style>
+
<!-- Icon displayed on the workspace -->
<style name="BaseIcon.Workspace" >
<item name="android:shadowRadius">2.0</item>
diff --git a/robolectric_tests/config/robolectric.properties b/robolectric_tests/config/robolectric.properties
index b171712..a8e0cb3 100644
--- a/robolectric_tests/config/robolectric.properties
+++ b/robolectric_tests/config/robolectric.properties
@@ -5,6 +5,7 @@
com.android.launcher3.shadows.LShadowAppWidgetManager \
com.android.launcher3.shadows.LShadowBackupManager \
com.android.launcher3.shadows.LShadowBitmap \
+ com.android.launcher3.shadows.LShadowDisplay \
com.android.launcher3.shadows.LShadowLauncherApps \
com.android.launcher3.shadows.LShadowTypeface \
com.android.launcher3.shadows.LShadowUserManager \
diff --git a/robolectric_tests/src/com/android/launcher3/shadows/LShadowDisplay.java b/robolectric_tests/src/com/android/launcher3/shadows/LShadowDisplay.java
new file mode 100644
index 0000000..3813fa1
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/shadows/LShadowDisplay.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 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.shadows;
+
+import static org.robolectric.shadow.api.Shadow.directlyOn;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.Display;
+
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.RealObject;
+import org.robolectric.shadows.ShadowDisplay;
+
+/**
+ * Extension of {@link ShadowDisplay} with missing shadow methods
+ */
+@Implements(value = Display.class)
+public class LShadowDisplay extends ShadowDisplay {
+
+ private final Rect mInsets = new Rect();
+
+ @RealObject Display realObject;
+
+ /**
+ * Sets the insets for the display
+ */
+ public void setInsets(Rect insets) {
+ mInsets.set(insets);
+ }
+
+ @Override
+ protected void getCurrentSizeRange(Point outSmallestSize, Point outLargestSize) {
+ directlyOn(realObject, Display.class).getCurrentSizeRange(outSmallestSize, outLargestSize);
+ outSmallestSize.x -= mInsets.left + mInsets.right;
+ outLargestSize.x -= mInsets.left + mInsets.right;
+
+ outSmallestSize.y -= mInsets.top + mInsets.bottom;
+ outLargestSize.y -= mInsets.top + mInsets.bottom;
+ }
+}
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 06a73db..cd938e1 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -16,6 +16,8 @@
package com.android.launcher3;
+import static androidx.dynamicanimation.animation.DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE;
+
import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
@@ -23,11 +25,13 @@
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherState.FLAG_HAS_SYS_UI_SCRIM;
import static com.android.launcher3.LauncherState.FLAG_WORKSPACE_HAS_BACKGROUNDS;
+import static com.android.launcher3.LauncherState.HINT_STATE;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
+import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.ZOOM_OUT;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
-import static com.android.launcher3.graphics.WorkspaceAndHotseatScrim.SCRIM_PROGRESS;
+import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS;
import static com.android.launcher3.graphics.WorkspaceAndHotseatScrim.SYSUI_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
@@ -35,6 +39,7 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
+import android.animation.ValueAnimator;
import android.view.View;
import android.view.animation.Interpolator;
@@ -43,8 +48,11 @@
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.util.DynamicResource;
+import com.android.systemui.plugins.ResourceProvider;
/**
* Manages the animations between each of the workspace states.
@@ -104,17 +112,32 @@
View qsbView = qsbScaleView.getSearchView();
if (playAtomicComponent) {
Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
- propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
+ LauncherState fromState = mLauncher.getStateManager().getState();
+ boolean shouldSpring = propertySetter instanceof PendingAnimation
+ && fromState == HINT_STATE && state == NORMAL;
+ if (shouldSpring) {
+ ((PendingAnimation) propertySetter).add(getSpringScaleAnimator(mLauncher,
+ mWorkspace, mNewScale));
+ } else {
+ propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
+ }
setPivotToScaleWithWorkspace(hotseat);
setPivotToScaleWithWorkspace(qsbScaleView);
float hotseatScale = hotseatScaleAndTranslation.scale;
- Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
- scaleInterpolator);
- propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale,
- hotseatScaleInterpolator);
- propertySetter.setFloat(qsbScaleView, SCALE_PROPERTY, qsbScaleAndTranslation.scale,
- hotseatScaleInterpolator);
+ if (shouldSpring) {
+ PendingAnimation pa = (PendingAnimation) propertySetter;
+ pa.add(getSpringScaleAnimator(mLauncher, hotseat, hotseatScale));
+ pa.add(getSpringScaleAnimator(mLauncher, qsbScaleView,
+ qsbScaleAndTranslation.scale));
+ } else {
+ Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
+ scaleInterpolator);
+ propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale,
+ hotseatScaleInterpolator);
+ propertySetter.setFloat(qsbScaleView, SCALE_PROPERTY, qsbScaleAndTranslation.scale,
+ hotseatScaleInterpolator);
+ }
float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, fadeInterpolator);
@@ -191,4 +214,24 @@
pageAlpha, fadeInterpolator);
}
}
+
+ /**
+ * Returns a spring based animator for the scale property of {@param v}.
+ */
+ public static ValueAnimator getSpringScaleAnimator(Launcher launcher, View v, float scale) {
+ ResourceProvider rp = DynamicResource.provider(launcher);
+ float damping = rp.getFloat(R.dimen.hint_scale_damping_ratio);
+ float stiffness = rp.getFloat(R.dimen.hint_scale_stiffness);
+ float velocityPxPerS = rp.getDimension(R.dimen.hint_scale_velocity_dp_per_s);
+
+ return new SpringAnimationBuilder(v.getContext())
+ .setStiffness(stiffness)
+ .setDampingRatio(damping)
+ .setMinimumVisibleChange(MIN_VISIBLE_CHANGE_SCALE)
+ .setEndValue(scale)
+ .setStartValue(SCALE_PROPERTY.get(v))
+ .setStartVelocity(velocityPxPerS)
+ .build(v, SCALE_PROPERTY);
+
+ }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 8df6f90..4f53d45 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -126,7 +126,7 @@
public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = getDebugFlag(
"ENABLE_HYBRID_HOTSEAT", true, "Fill gaps in hotseat with predicted apps");
- public static final BooleanFlag HOTSEAT_MIGRATE_TO_FOLDER = new DeviceFlag(
+ public static final BooleanFlag HOTSEAT_MIGRATE_TO_FOLDER = getDebugFlag(
"HOTSEAT_MIGRATE_TO_FOLDER", false, "Should move hotseat items into a folder");
public static final BooleanFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = getDebugFlag(
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index a0e6bfc..82d61da 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -19,9 +19,8 @@
import androidx.annotation.Nullable;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
-import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
import com.android.launcher3.logging.StatsLogUtils.LogStateProvider;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.ResourceBasedOverride;
@@ -145,12 +144,20 @@
@UiEvent(doc = "Hotseat education tip shown")
LAUNCHER_HOTSEAT_EDU_ONLY_TIP(482),
+ /**
+ * @deprecated LauncherUiChanged.rank field is repurposed to store all apps rank, so no
+ * separate event is required.
+ */
+ @Deprecated
@UiEvent(doc = "App launch ranking logged for all apps predictions")
LAUNCHER_ALL_APPS_RANKED(552),
@UiEvent(doc = "App launch ranking logged for hotseat predictions)")
LAUNCHER_HOTSEAT_RANKED(553),
+ @UiEvent(doc = "User's workspace layout information is snapshot in the background.")
+ LAUNCHER_WORKSPACE_SNAPSHOT(579),
+
@UiEvent(doc = "User tapped on the screenshot button on overview)")
LAUNCHER_OVERVIEW_ACTIONS_SCREENSHOT(580),
@@ -165,6 +172,7 @@
@UiEvent(doc = "User tapped on the highlight items in select mode")
LAUNCHER_SELECT_MODE_ITEM(584);
+
// ADD MORE
private final int mId;
@@ -238,6 +246,16 @@
}
/**
+ * Sets the final value for container related fields of log message.
+ *
+ * By default container related fields are derived from {@link ItemInfo}, this method would
+ * override those values.
+ */
+ default StatsLogger withContainerInfo(ContainerInfo containerInfo) {
+ return this;
+ }
+
+ /**
* Builds the final message and logs it as {@link EventEnum}.
*/
default void log(EventEnum event) {
@@ -269,25 +287,6 @@
}
/**
- * Logs an event.
- *
- * @param event an enum implementing EventEnum interface.
- * @param atomInfo item typically containing app or task launch related information.
- */
- public void log(EventEnum event, InstanceId instanceId, LauncherAtom.ItemInfo atomInfo) {
- }
-
- /**
- * Logs an event and accompanying {@link LauncherState}s.
- *
- * @param event an enum implementing EventEnum interface.
- * @param launcherAtomItemInfo item typically containing app or task launch related information.
- */
- public void log(EventEnum event, @Nullable LauncherAtom.ItemInfo launcherAtomItemInfo,
- int srcState, int dstState) {
- }
-
- /**
* Log an event with ranked-choice information along with package. Does nothing if event.getId()
* <= 0.
*
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index 9ea8436..b8a184f 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -39,8 +39,18 @@
}
@Override
+ protected float getDepthUnchecked(Context context) {
+ return 0.15f;
+ }
+
+ @Override
+ public float getOverviewScrimAlpha(Launcher launcher) {
+ return 0.4f;
+ }
+
+ @Override
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
- return new ScaleAndTranslation(0.9f, 0, 0);
+ return new ScaleAndTranslation(0.92f, 0, 0);
}
@Override
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index e786f07..38b3712 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -15,27 +15,17 @@
*/
package com.android.launcher3.testing;
-import static android.graphics.Bitmap.Config.ARGB_8888;
-
import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Color;
import android.graphics.Insets;
import android.os.Build;
import android.os.Bundle;
-import android.os.Debug;
-import android.system.Os;
-import android.util.Log;
-import android.view.View;
import android.view.WindowInsets;
-import androidx.annotation.Keep;
-
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
@@ -44,10 +34,7 @@
import com.android.launcher3.R;
import com.android.launcher3.util.ResourceBasedOverride;
-import java.util.LinkedList;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -65,7 +52,6 @@
protected Context mContext;
protected DeviceProfile mDeviceProfile;
protected LauncherAppState mLauncherAppState;
- private static LinkedList mLeaks;
public void init(Context context) {
mContext = context;
@@ -77,15 +63,6 @@
public Bundle call(String method) {
final Bundle response = new Bundle();
switch (method) {
- case TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT: {
- return getLauncherUIProperty(Bundle::putInt, l -> {
- final float progress = LauncherState.OVERVIEW.getVerticalProgress(l)
- - LauncherState.ALL_APPS.getVerticalProgress(l);
- final float distance = l.getAllAppsController().getShiftRange() * progress;
- return (int) distance;
- });
- }
-
case TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT: {
return getLauncherUIProperty(Bundle::putInt, l -> {
final float progress = LauncherState.NORMAL.getVerticalProgress(l)
@@ -99,14 +76,6 @@
return getUIProperty(Bundle::putBoolean, t -> isLauncherInitialized(), () -> true);
}
- case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
- TestProtocol.sDebugTracing = true;
- break;
-
- case TestProtocol.REQUEST_DISABLE_DEBUG_TRACING:
- TestProtocol.sDebugTracing = false;
- break;
-
case TestProtocol.REQUEST_FREEZE_APP_LIST:
return getLauncherUIProperty(Bundle::putBoolean, l -> {
l.getAppsView().getAppsStore().enableDeferUpdates(DEFER_UPDATES_TEST);
@@ -118,11 +87,6 @@
return true;
});
- case TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS: {
- return getLauncherUIProperty(Bundle::putInt,
- l -> l.getAppsView().getAppsStore().getDeferUpdatesFlags());
- }
-
case TestProtocol.REQUEST_APPS_LIST_SCROLL_Y: {
return getLauncherUIProperty(Bundle::putInt,
l -> l.getAppsView().getActiveRecyclerView().getCurrentScrollY());
@@ -137,59 +101,19 @@
}, this::getCurrentActivity);
}
- case TestProtocol.REQUEST_PID: {
- response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, Os.getpid());
- break;
- }
-
- case TestProtocol.REQUEST_TOTAL_PSS_KB: {
- runGcAndFinalizersSync();
- Debug.MemoryInfo mem = new Debug.MemoryInfo();
- Debug.getMemoryInfo(mem);
- response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, mem.getTotalPss());
- break;
- }
-
- case TestProtocol.REQUEST_JAVA_LEAK: {
- if (mLeaks == null) mLeaks = new LinkedList();
-
- // Allocate and dirty the memory.
- final int leakSize = 1024 * 1024;
- final byte[] bytes = new byte[leakSize];
- for (int i = 0; i < leakSize; i += 239) {
- bytes[i] = (byte) (i % 256);
- }
- mLeaks.add(bytes);
- break;
- }
-
- case TestProtocol.REQUEST_NATIVE_LEAK: {
- if (mLeaks == null) mLeaks = new LinkedList();
-
- // Allocate and dirty a bitmap.
- final Bitmap bitmap = Bitmap.createBitmap(512, 512, ARGB_8888);
- bitmap.eraseColor(Color.RED);
- mLeaks.add(bitmap);
- break;
- }
-
- case TestProtocol.REQUEST_VIEW_LEAK: {
- if (mLeaks == null) mLeaks = new LinkedList();
- mLeaks.add(new View(mContext));
- break;
- }
-
case TestProtocol.REQUEST_ICON_HEIGHT: {
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
mDeviceProfile.allAppsCellHeightPx);
- break;
+ return response;
}
case TestProtocol.REQUEST_MOCK_SENSOR_ROTATION:
TestProtocol.sDisableSensorRotation = true;
- break;
+ return response;
+
+ default:
+ return null;
}
- return response;
}
protected boolean isLauncherInitialized() {
@@ -201,22 +125,6 @@
return Launcher.ACTIVITY_TRACKER.getCreatedActivity();
}
- private static void runGcAndFinalizersSync() {
- Runtime.getRuntime().gc();
- Runtime.getRuntime().runFinalization();
-
- final CountDownLatch fence = new CountDownLatch(1);
- createFinalizationObserver(fence);
- try {
- do {
- Runtime.getRuntime().gc();
- Runtime.getRuntime().runFinalization();
- } while (!fence.await(100, TimeUnit.MILLISECONDS));
- } catch (InterruptedException ex) {
- throw new RuntimeException(ex);
- }
- }
-
/**
* Returns the result by getting a Launcher property on UI thread
*/
@@ -257,21 +165,4 @@
*/
void set(Bundle b, String key, T value);
}
-
- // Create the observer in the scope of a method to minimize the chance that
- // it remains live in a DEX/machine register at the point of the fence guard.
- // This must be kept to avoid R8 inlining it.
- @Keep
- private static void createFinalizationObserver(CountDownLatch fence) {
- new Object() {
- @Override
- protected void finalize() throws Throwable {
- try {
- fence.countDown();
- } finally {
- super.finalize();
- }
- }
- };
- }
}
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index 90a1c82..d4e074c 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -38,6 +38,7 @@
public static final String SHELF_BOUNCE_COUNT = "launcher.shelf_bounce_count";
public static final String ALL_APPS_COUNT = "launcher.all_apps_count";
public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count";
+ public static final String HOTSEAT_LONGPRESS_TIP_SEEN = "launcher.hotseat_longpress_tip_seen";
/**
* Events that either have happened or have not (booleans).
@@ -99,6 +100,13 @@
}
/**
+ * Marks on-boarding preference boolean at true
+ */
+ public void markChecked(String flag) {
+ mSharedPrefs.edit().putBoolean(flag, true).apply();
+ }
+
+ /**
* Add 1 to the given event count, if we haven't already reached the max count.
* @return Whether we have now reached the max count.
*/
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 7cce044..3d39d25 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -294,7 +294,8 @@
// Limits UI tests affecting tests running after them.
mLauncher.waitForLauncherInitialized();
if (mLauncherPid != 0) {
- assertEquals("Launcher crashed, pid mismatch:", mLauncherPid, mLauncher.getPid());
+ assertEquals("Launcher crashed, pid mismatch:",
+ mLauncherPid, mLauncher.getPid().intValue());
}
checkDetectedLeaks(mLauncher);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 808be66..b6c17df 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -18,6 +18,7 @@
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Bundle;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -244,8 +245,8 @@
}
private void verifyNotFrozen(String message) {
- mLauncher.assertEquals(message, 0, mLauncher.getTestInfo(
- TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS).
- getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD));
+ final Bundle testInfo = mLauncher.getTestInfo(TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS);
+ if (testInfo == null) return;
+ mLauncher.assertEquals(message, 0, testInfo.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD));
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 7ddb492..9f4d9ce 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1309,8 +1309,9 @@
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
- public int getPid() {
- return getTestInfo(TestProtocol.REQUEST_PID).getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ public Integer getPid() {
+ final Bundle testInfo = getTestInfo(TestProtocol.REQUEST_PID);
+ return testInfo != null ? testInfo.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD) : null;
}
public void produceJavaLeak() {
@@ -1338,13 +1339,13 @@
public Closable eventsCheck() {
Assert.assertTrue("Nested event checking", !sCheckingEvents);
disableSensorRotation();
- final int initialPid = getPid();
+ final Integer initialPid = getPid();
if (sEventChecker == null) sEventChecker = new LogEventChecker();
sEventChecker.start();
sCheckingEvents = true;
return () -> {
- if (initialPid != getPid()) {
+ if (initialPid != null && initialPid.intValue() != getPid()) {
if (mOnLauncherCrashed != null) mOnLauncherCrashed.run();
checkForAnomaly();
Assert.fail(