Fix launcher crash after restore with some specific widgets. am: 8dae83ee9b am: 12ef632d00 am: b446d1069b
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/12196250
Change-Id: Ibaa44b172006576d642a19569b0973c50e54f80b
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index ff5bf0d..19a16e3 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -45,9 +45,6 @@
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
-
- <!-- TODO(b/150802536): Enabled only for ENABLE_FIXED_ROTATION_TRANSFORM feature flag -->
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
<!--
Permissions required for read/write access to the workspace data. These permission name
@@ -86,6 +83,7 @@
<receiver
android:name="com.android.launcher3.InstallShortcutReceiver"
android:permission="com.android.launcher.permission.INSTALL_SHORTCUT"
+ android:exported="true"
android:enabled="@bool/enable_install_shortcut_api" >
<intent-filter>
<action android:name="com.android.launcher.action.INSTALL_SHORTCUT" />
@@ -94,14 +92,16 @@
<!-- Intent received when a session is committed -->
<receiver
- android:name="com.android.launcher3.SessionCommitReceiver" >
+ android:name="com.android.launcher3.SessionCommitReceiver"
+ android:exported="true">
<intent-filter>
<action android:name="android.content.pm.action.SESSION_COMMITTED" />
</intent-filter>
</receiver>
<!-- Intent received used to initialize a restored widget -->
- <receiver android:name="com.android.launcher3.AppWidgetsRestoredReceiver" >
+ <receiver android:name="com.android.launcher3.AppWidgetsRestoredReceiver"
+ android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_HOST_RESTORED"/>
</intent-filter>
@@ -117,6 +117,7 @@
android:name="com.android.launcher3.notification.NotificationListener"
android:label="@string/notification_dots_service_title"
android:enabled="@bool/notification_dots_enabled"
+ android:exported="true"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
@@ -130,6 +131,7 @@
android:theme="@style/AppItemActivityTheme"
android:excludeFromRecents="true"
android:autoRemoveFromRecents="true"
+ android:exported="true"
android:label="@string/action_add_to_workspace" >
<intent-filter>
<action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
@@ -165,6 +167,7 @@
android:name="com.android.launcher3.settings.SettingsActivity"
android:label="@string/settings_button_text"
android:theme="@style/HomeSettingsTheme"
+ android:exported="true"
android:autoRemoveFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
@@ -187,6 +190,7 @@
android:name="com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher"
android:theme="@style/AppTheme"
android:launchMode="singleTop"
+ android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b031ffb..8e01f82 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -53,6 +53,7 @@
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
+ android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
index e649ce1..aa3710b 100644
--- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
+++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
@@ -164,6 +164,12 @@
}
case TestProtocol.REQUEST_GET_TEST_EVENTS: {
+ if (sEvents == null) {
+ // sEvents can be null if Launcher died and restarted after
+ // REQUEST_START_EVENT_LOGGING.
+ return response;
+ }
+
synchronized (sEvents) {
response.putStringArrayList(
TestProtocol.TEST_INFO_RESPONSE_FIELD, new ArrayList<>(sEvents));
diff --git a/quickstep/AndroidManifest-launcher.xml b/quickstep/AndroidManifest-launcher.xml
index 60afddb..53910e3 100644
--- a/quickstep/AndroidManifest-launcher.xml
+++ b/quickstep/AndroidManifest-launcher.xml
@@ -53,6 +53,7 @@
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
+ android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index e49f2ec..4e7c3fa 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -17,97 +17,91 @@
** limitations under the License.
*/
-->
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="com.android.launcher3" >
- <permission
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ 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="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"
- android:fullBackupContent="@xml/backupscheme"
- android:hardwareAccelerated="true"
- android:icon="@drawable/ic_launcher_home"
- android:label="@string/derived_app_name"
- android:theme="@style/AppTheme"
- android:largeHeap="@bool/config_largeHeap"
- android:restoreAnyVersion="true"
- android:supportsRtl="true" >
+ <application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
+ android:fullBackupOnly="true"
+ android:fullBackupContent="@xml/backupscheme"
+ android:hardwareAccelerated="true"
+ android:icon="@drawable/ic_launcher_home"
+ android:label="@string/derived_app_name"
+ android:theme="@style/AppTheme"
+ android:largeHeap="@bool/config_largeHeap"
+ android:restoreAnyVersion="true"
+ android:supportsRtl="true">
- <service
- android:name="com.android.quickstep.TouchInteractionService"
- android:permission="android.permission.STATUS_BAR_SERVICE"
- android:directBootAware="true" >
+ <service android:name="com.android.quickstep.TouchInteractionService"
+ android:permission="android.permission.STATUS_BAR_SERVICE"
+ android:directBootAware="true"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.QUICKSTEP_SERVICE" />
+ <action android:name="android.intent.action.QUICKSTEP_SERVICE"/>
</intent-filter>
</service>
<activity android:name="com.android.quickstep.RecentsActivity"
- android:excludeFromRecents="true"
- android:launchMode="singleTask"
- android:clearTaskOnLaunch="true"
- android:stateNotNeeded="true"
- android:theme="@style/LauncherTheme"
- android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
- android:resizeableActivity="true"
- android:resumeWhilePausing="true"
- android:taskAffinity="" />
+ android:excludeFromRecents="true"
+ android:launchMode="singleTask"
+ android:clearTaskOnLaunch="true"
+ android:stateNotNeeded="true"
+ android:theme="@style/LauncherTheme"
+ android:screenOrientation="unspecified"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
+ android:resizeableActivity="true"
+ android:resumeWhilePausing="true"
+ android:taskAffinity=""/>
<!-- Content provider to settings search. The autority should be same as the packageName -->
- <provider
- android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
- android:authorities="${packageName}"
- android:grantUriPermissions="true"
- android:multiprocess="true"
- android:permission="android.permission.READ_SEARCH_INDEXABLES"
- android:exported="true">
+ <provider android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
+ android:authorities="${packageName}"
+ android:grantUriPermissions="true"
+ android:multiprocess="true"
+ android:permission="android.permission.READ_SEARCH_INDEXABLES"
+ android:exported="true">
<intent-filter>
- <action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" />
+ <action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER"/>
</intent-filter>
</provider>
<!-- FileProvider used for sharing images. -->
- <provider
- android:name="androidx.core.content.FileProvider"
- android:authorities="${packageName}.overview.fileprovider"
- android:exported="false"
- android:grantUriPermissions="true">
- <meta-data
- android:name="android.support.FILE_PROVIDER_PATHS"
- android:resource="@xml/overview_file_provider_paths" />
+ <provider android:name="androidx.core.content.FileProvider"
+ android:authorities="${packageName}.overview.fileprovider"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/overview_file_provider_paths"/>
</provider>
- <service
- android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
- tools:node="remove" />
+ <service android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
+ tools:node="remove"/>
- <activity
- android:name="com.android.launcher3.proxy.ProxyActivityStarter"
- android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
- android:launchMode="singleTask"
- android:clearTaskOnLaunch="true"
- android:exported="false" />
+ <activity android:name="com.android.launcher3.proxy.ProxyActivityStarter"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
+ android:launchMode="singleTask"
+ android:clearTaskOnLaunch="true"
+ android:exported="false"/>
- <activity
- android:name="com.android.quickstep.interaction.GestureSandboxActivity"
- android:autoRemoveFromRecents="true"
- android:excludeFromRecents="true"
- android:screenOrientation="portrait">
+ <activity android:name="com.android.quickstep.interaction.GestureSandboxActivity"
+ android:autoRemoveFromRecents="true"
+ android:excludeFromRecents="true"
+ android:screenOrientation="portrait"
+ android:exported="true">
<intent-filter>
- <action android:name="com.android.quickstep.action.GESTURE_SANDBOX" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="com.android.quickstep.action.GESTURE_SANDBOX"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
@@ -116,7 +110,8 @@
android:noHistory="true"
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
- android:permission="${packageName}.permission.HOTSEAT_EDU">
+ android:permission="${packageName}.permission.HOTSEAT_EDU"
+ android:exported="true">
<intent-filter>
<action android:name="com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU"/>
<category android:name="android.intent.category.DEFAULT" />
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java
index 4c7943b..e4442da 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java
@@ -69,7 +69,6 @@
// Accessed only on worker thread
private AppPredictor mHomeAppPredictor;
- private AppPredictor mRecentsOverviewPredictor;
public PredictionAppTracker(Context context) {
mContext = context;
@@ -97,10 +96,6 @@
mHomeAppPredictor.destroy();
mHomeAppPredictor = null;
}
- if (mRecentsOverviewPredictor != null) {
- mRecentsOverviewPredictor.destroy();
- mRecentsOverviewPredictor = null;
- }
}
@WorkerThread
@@ -142,7 +137,6 @@
// Initialize the clients
int count = InvariantDeviceProfile.INSTANCE.get(mContext).numAllAppsColumns;
mHomeAppPredictor = createPredictor(Client.HOME, count);
- mRecentsOverviewPredictor = createPredictor(Client.OVERVIEW, count);
return true;
}
case MSG_DESTROY: {
@@ -157,12 +151,7 @@
}
case MSG_PREDICT: {
if (mHomeAppPredictor != null) {
- String client = (String) msg.obj;
- if (Client.HOME.id.equals(client)) {
- mHomeAppPredictor.requestPredictionUpdate();
- } else {
- mRecentsOverviewPredictor.requestPredictionUpdate();
- }
+ mHomeAppPredictor.requestPredictionUpdate();
}
return true;
}
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 a0f6b04..830c103 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
@@ -75,8 +75,7 @@
// TODO (b/129421797): Update the client constants
public enum Client {
- HOME("home"),
- OVERVIEW("overview");
+ HOME("home");
public final String id;
@@ -91,10 +90,9 @@
private final Context mContext;
private final DynamicItemCache mDynamicItemCache;
- private final List[] mPredictionServicePredictions;
+ private List mPredictionServicePredictions = Collections.emptyList();
private int mMaxIconsPerRow;
- private Client mActiveClient;
private AllAppsContainerView mAppsView;
@@ -108,16 +106,10 @@
mDynamicItemCache = new DynamicItemCache(context, this::onAppsUpdated);
- mActiveClient = Client.HOME;
-
InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
mMaxIconsPerRow = idp.numColumns;
idp.addOnChangeListener(this);
- mPredictionServicePredictions = new List[Client.values().length];
- for (int i = 0; i < mPredictionServicePredictions.length; i++) {
- mPredictionServicePredictions[i] = Collections.emptyList();
- }
mGettingValidPredictionResults = Utilities.getDevicePrefs(context)
.getBoolean(LAST_PREDICTION_ENABLED_STATE, true);
@@ -130,18 +122,6 @@
mMaxIconsPerRow = profile.numColumns;
}
- public Client getClient() {
- return mActiveClient;
- }
-
- public void switchClient(Client client) {
- if (client == mActiveClient) {
- return;
- }
- mActiveClient = client;
- dispatchOnChange(true);
- }
-
public void setTargetAppsView(AllAppsContainerView appsView) {
if (mAppsView != null) {
mAppsView.getAppsStore().removeUpdateListener(this);
@@ -195,10 +175,8 @@
}
private void updatePredictionStateAfterCallback() {
- boolean validResults = false;
- for (List l : mPredictionServicePredictions) {
- validResults |= l != null && !l.isEmpty();
- }
+ boolean validResults = mPredictionServicePredictions != null
+ && !mPredictionServicePredictions.isEmpty();
if (validResults != mGettingValidPredictionResults) {
mGettingValidPredictionResults = validResults;
Utilities.getDevicePrefs(mContext).edit()
@@ -210,7 +188,7 @@
public AppPredictor.Callback appPredictorCallback(Client client) {
return targets -> {
- mPredictionServicePredictions[client.ordinal()] = targets;
+ mPredictionServicePredictions = targets;
updatePredictionStateAfterCallback();
};
}
@@ -238,7 +216,7 @@
state.apps = new ArrayList<>();
- List<AppTarget> appTargets = mPredictionServicePredictions[mActiveClient.ordinal()];
+ List<AppTarget> appTargets = mPredictionServicePredictions;
if (!appTargets.isEmpty()) {
for (AppTarget appTarget : appTargets) {
ComponentKey key;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index de83caf..9310685 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -24,6 +24,7 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
+import android.app.ActivityManager.RunningTaskInfo;
import android.util.Log;
import android.view.animation.Interpolator;
@@ -52,17 +53,17 @@
private final BaseActivityInterface<?, T> mActivityInterface;
// The id of the currently running task that is transitioning to overview.
- private final int mTargetTaskId;
+ private final RunningTaskInfo mTargetTask;
private final RecentsAnimationDeviceState mDeviceState;
private T mActivity;
private RecentsView mRecentsView;
AppToOverviewAnimationProvider(
- BaseActivityInterface<?, T> activityInterface, int targetTaskId,
+ BaseActivityInterface<?, T> activityInterface, RunningTaskInfo targetTask,
RecentsAnimationDeviceState deviceState) {
mActivityInterface = activityInterface;
- mTargetTaskId = targetTaskId;
+ mTargetTask = targetTask;
mDeviceState = deviceState;
}
@@ -73,7 +74,7 @@
* @param wasVisible true if it was visible before
*/
boolean onActivityReady(T activity, Boolean wasVisible) {
- activity.<RecentsView>getOverviewPanel().showCurrentTask(mTargetTaskId);
+ activity.<RecentsView>getOverviewPanel().showCurrentTask(mTargetTask);
AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
BaseActivityInterface.AnimationFactory factory = mActivityInterface.prepareRecentsUI(
mDeviceState,
@@ -122,7 +123,8 @@
wallpaperTargets, MODE_CLOSING);
// Use the top closing app to determine the insets for the animation
- RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mTargetTaskId);
+ RemoteAnimationTargetCompat runningTaskTarget = mTargetTask == null ? null
+ : targets.findTask(mTargetTask.taskId);
if (runningTaskTarget == null) {
Log.e(TAG, "No closing app");
return pa.buildAnim();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
index 6c4c5d3..bf03587 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
@@ -38,7 +38,6 @@
import static com.android.quickstep.GestureState.STATE_END_TARGET_SET;
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
-import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
@@ -313,12 +312,6 @@
}
setupRecentsViewUi();
-
- if (mDeviceState.getNavMode() == TWO_BUTTONS) {
- // If the device is in two button mode, swiping up will show overview with predictions
- // so we need to kick off switching to the overview predictions as soon as possible
- mActivityInterface.updateOverviewPredictionState();
- }
linkRecentsViewScroll();
return true;
@@ -423,7 +416,7 @@
}
protected void notifyGestureAnimationStartToRecents() {
- mRecentsView.onGestureAnimationStart(mGestureState.getRunningTaskId());
+ mRecentsView.onGestureAnimationStart(mGestureState.getRunningTask());
}
private void launcherFrameDrawn() {
@@ -451,12 +444,6 @@
@Override
public void onMotionPauseChanged(boolean isPaused) {
setShelfState(isPaused ? PEEK : HIDE, ShelfPeekAnim.INTERPOLATOR, ShelfPeekAnim.DURATION);
-
- if (mDeviceState.isFullyGesturalNavMode() && isPaused) {
- // In fully gestural nav mode, switch to overview predictions once the user has paused
- // (this is a no-op if the predictions are already in that state)
- mActivityInterface.updateOverviewPredictionState();
- }
}
public void maybeUpdateRecentsAttachedState() {
@@ -555,14 +542,6 @@
@Override
public void updateFinalShift() {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- if (mRecentsAnimationTargets != null) {
- LiveTileOverlay.INSTANCE.update(
- mTaskViewSimulator.getCurrentCropRect(),
- mTaskViewSimulator.getCurrentCornerRadius());
- }
- }
-
final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW;
if (passed != mPassedOverviewThreshold) {
mPassedOverviewThreshold = passed;
@@ -573,6 +552,14 @@
updateSysUiFlags(mCurrentShift.value);
applyWindowTransform();
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ if (mRecentsAnimationTargets != null) {
+ LiveTileOverlay.INSTANCE.update(
+ mTaskViewSimulator.getCurrentRect(),
+ mTaskViewSimulator.getCurrentCornerRadius());
+ }
+ }
+
updateLauncherTransitionProgress();
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
index edefbe1..6621b41 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
@@ -262,16 +262,6 @@
}
@Override
- public void updateOverviewPredictionState() {
- Launcher launcher = getCreatedActivity();
- if (launcher == null) {
- return;
- }
- PredictionUiStateManager.INSTANCE.get(launcher).switchClient(
- PredictionUiStateManager.Client.OVERVIEW);
- }
-
- @Override
public int getContainerType() {
final Launcher launcher = getVisibleLauncher();
return launcher != null ? launcher.getStateManager().getState().containerType
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
index 434a929..dca3378 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
@@ -29,7 +29,6 @@
import androidx.annotation.BinderThread;
-import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -165,7 +164,7 @@
mActivityInterface = mOverviewComponentObserver.getActivityInterface();
mCreateTime = SystemClock.elapsedRealtime();
mAnimationProvider = new AppToOverviewAnimationProvider<>(mActivityInterface,
- RecentsModel.getRunningTaskId(), mDeviceState);
+ ActivityManagerWrapper.getInstance().getRunningTask(), mDeviceState);
// Preload the plan
mRecentsModel.getTasks(null);
@@ -227,10 +226,6 @@
LauncherLogProto.ContainerType.TASKSWITCHER);
mUserEventLogged = true;
}
-
- // Switch prediction client to overview
- PredictionUiStateManager.INSTANCE.get(activity).switchClient(
- PredictionUiStateManager.Client.OVERVIEW);
return mAnimationProvider.onActivityReady(activity, wasVisible);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 6e0b517..a3705fd 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -58,6 +58,7 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
+import com.android.launcher3.ResourceUtils;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.UserEventDispatcher;
@@ -75,6 +76,7 @@
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
import com.android.quickstep.inputconsumers.AssistantInputConsumer;
import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
+import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
import com.android.quickstep.inputconsumers.OverscrollInputConsumer;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
@@ -297,6 +299,7 @@
mAM = ActivityManagerWrapper.getInstance();
mDeviceState = new RecentsAnimationDeviceState(this);
mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
+ mDeviceState.addOneHandedModeChangedCallback(this::onOneHandedModeOverlayChanged);
mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
ProtoTracer.INSTANCE.get(this).add(this);
@@ -337,6 +340,13 @@
resetHomeBounceSeenOnQuickstepEnabledFirstTime();
}
+ /**
+ * Called when the one handed mode overlay package changes, to recreate touch region.
+ */
+ private void onOneHandedModeOverlayChanged(int newGesturalHeight) {
+ initInputMonitor();
+ }
+
@UiThread
public void onUserUnlocked() {
mTaskAnimationManager = new TaskAnimationManager();
@@ -502,6 +512,11 @@
} else {
mUncheckedConsumer = InputConsumer.NO_OP;
}
+ } else if (mDeviceState.canTriggerOneHandedAction(event)
+ && !mDeviceState.isOneHandedModeActive()) {
+ // Consume gesture event for triggering one handed feature.
+ mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState,
+ InputConsumer.NO_OP, mInputMonitorCompat);
} else {
mUncheckedConsumer = InputConsumer.NO_OP;
}
@@ -626,6 +641,11 @@
base = new ScreenPinnedInputConsumer(this, newGestureState);
}
+ if (mDeviceState.canTriggerOneHandedAction(event)) {
+ base = new OneHandedModeInputConsumer(this, mDeviceState, base,
+ mInputMonitorCompat);
+ }
+
if (mDeviceState.isAccessibilityMenuAvailable()) {
base = new AccessibilityInputConsumer(this, mDeviceState, base,
mInputMonitorCompat);
@@ -634,6 +654,11 @@
if (mDeviceState.isScreenPinningActive()) {
base = mResetGestureInputConsumer;
}
+
+ if (mDeviceState.canTriggerOneHandedAction(event)) {
+ base = new OneHandedModeInputConsumer(this, mDeviceState, base,
+ mInputMonitorCompat);
+ }
}
return base;
}
@@ -801,6 +826,13 @@
}
if (mOverviewComponentObserver.canHandleConfigChanges(activity.getComponentName(),
activity.getResources().getConfiguration().diff(newConfig))) {
+ // Since navBar gestural height are different between portrait and landscape,
+ // can handle orientation changes and refresh navigation gestural region through
+ // onOneHandedModeChanged()
+ int newGesturalHeight = ResourceUtils.getNavbarSize(
+ ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE,
+ getApplicationContext().getResources());
+ mDeviceState.onOneHandedModeChanged(newGesturalHeight);
return;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
index d20bbe9..ffe9d6a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -76,7 +76,7 @@
*/
public void onGestureAnimationStartOnHome(RunningTaskInfo homeTaskInfo) {
mHomeTaskInfo = homeTaskInfo;
- onGestureAnimationStart(homeTaskInfo == null ? -1 : homeTaskInfo.taskId);
+ onGestureAnimationStart(homeTaskInfo);
}
/**
@@ -107,14 +107,15 @@
}
@Override
- protected boolean shouldAddDummyTaskView(int runningTaskId) {
- if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == runningTaskId
+ protected boolean shouldAddDummyTaskView(RunningTaskInfo runningTaskInfo) {
+ if (mHomeTaskInfo != null && runningTaskInfo != null &&
+ mHomeTaskInfo.taskId == runningTaskInfo.taskId
&& getTaskViewCount() == 0) {
// Do not add a dummy task if we are running over home with empty recents, so that we
// show the empty recents message instead of showing a dummy task and later removing it.
return false;
}
- return super.shouldAddDummyTaskView(runningTaskId);
+ return super.shouldAddDummyTaskView(runningTaskInfo);
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java
new file mode 100644
index 0000000..0bb8fff
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.inputconsumers;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+
+import static com.android.launcher3.Utilities.squaredHypot;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.view.MotionEvent;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.quickstep.InputConsumer;
+import com.android.quickstep.RecentsAnimationDeviceState;
+import com.android.quickstep.SystemUiProxy;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+/**
+ * Touch consumer for handling gesture event to launch one handed
+ * One handed gestural in quickstep only active on NO_BUTTON, TWO_BUTTONS, and portrait mode
+ */
+public class OneHandedModeInputConsumer extends DelegateInputConsumer {
+
+ private static final String TAG = "OneHandedModeInputConsumer";
+ private static final int ANGLE_MAX = 150;
+ private static final int ANGLE_MIN = 30;
+
+ private final Context mContext;
+ private final RecentsAnimationDeviceState mDeviceState;
+
+ private final float mDragDistThreshold;
+ private final float mSquaredSlop;
+
+ private final PointF mDownPos = new PointF();
+ private final PointF mLastPos = new PointF();
+ private final PointF mStartDragPos = new PointF();
+
+ private boolean mPassedSlop;
+
+ public OneHandedModeInputConsumer(Context context, RecentsAnimationDeviceState deviceState,
+ InputConsumer delegate, InputMonitorCompat inputMonitor) {
+ super(delegate, inputMonitor);
+ mContext = context;
+ mDeviceState = deviceState;
+ mDragDistThreshold = context.getResources().getDimensionPixelSize(
+ R.dimen.gestures_onehanded_drag_threshold);
+ mSquaredSlop = Utilities.squaredTouchSlop(context);
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_ONE_HANDED | mDelegate.getType();
+ }
+
+ @Override
+ public void onMotionEvent(MotionEvent ev) {
+ switch (ev.getActionMasked()) {
+ case ACTION_DOWN: {
+ mDownPos.set(ev.getX(), ev.getY());
+ mLastPos.set(mDownPos);
+ break;
+ }
+ case ACTION_MOVE: {
+ if (mState == STATE_DELEGATE_ACTIVE) {
+ break;
+ }
+ if (!mDelegate.allowInterceptByParent()) {
+ mState = STATE_DELEGATE_ACTIVE;
+ break;
+ }
+
+ mLastPos.set(ev.getX(), ev.getY());
+ if (!mPassedSlop) {
+ if (squaredHypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y)
+ > mSquaredSlop) {
+ mStartDragPos.set(mLastPos.x, mLastPos.y);
+ if ((!mDeviceState.isOneHandedModeActive() && isValidStartAngle(
+ mDownPos.x - mLastPos.x, mDownPos.y - mLastPos.y))
+ || (mDeviceState.isOneHandedModeActive() && isValidExitAngle(
+ mDownPos.x - mLastPos.x, mDownPos.y - mLastPos.y))) {
+ mPassedSlop = true;
+ setActive(ev);
+ } else {
+ mState = STATE_DELEGATE_ACTIVE;
+ }
+ }
+ } else {
+ float distance = (float) Math.hypot(mLastPos.x - mStartDragPos.x,
+ mLastPos.y - mStartDragPos.y);
+ if (distance > mDragDistThreshold && mPassedSlop) {
+ onStopGestureDetected();
+ }
+ }
+ break;
+ }
+ case ACTION_UP:
+ case ACTION_CANCEL: {
+ if (mLastPos.y >= mStartDragPos.y && mPassedSlop) {
+ onStartGestureDetected();
+ }
+
+ mPassedSlop = false;
+ mState = STATE_INACTIVE;
+ break;
+ }
+ }
+
+ if (mState != STATE_ACTIVE) {
+ mDelegate.onMotionEvent(ev);
+ }
+ }
+
+ private void onStartGestureDetected() {
+ if (mDeviceState.isOneHandedModeEnabled()) {
+ if (!mDeviceState.isOneHandedModeActive()) {
+ SystemUiProxy.INSTANCE.get(mContext).startOneHandedMode();
+ }
+ } else if (mDeviceState.isSwipeToNotificationEnabled()) {
+ SystemUiProxy.INSTANCE.get(mContext).expandNotificationPanel();
+ }
+ }
+
+ private void onStopGestureDetected() {
+ if (!mDeviceState.isOneHandedModeEnabled() || !mDeviceState.isOneHandedModeActive()) {
+ return;
+ }
+
+ SystemUiProxy.INSTANCE.get(mContext).stopOneHandedMode();
+ }
+
+ private boolean isValidStartAngle(float deltaX, float deltaY) {
+ final float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
+ return angle > -(ANGLE_MAX) && angle < -(ANGLE_MIN);
+ }
+
+ private boolean isValidExitAngle(float deltaX, float deltaY) {
+ final float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
+ return angle > ANGLE_MIN && angle < ANGLE_MAX;
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 3cafd42..4120331 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -205,13 +205,15 @@
ResourceProvider rp = DynamicResource.provider(v.getContext());
float stiffness = rp.getFloat(R.dimen.staggered_stiffness);
float damping = rp.getFloat(R.dimen.staggered_damping_ratio);
+ float endTransY = 0;
+ float springVelocity = Math.abs(mVelocity) * Math.signum(endTransY - mSpringTransY);
ValueAnimator springTransY = new SpringAnimationBuilder(v.getContext())
.setStiffness(stiffness)
.setDampingRatio(damping)
.setMinimumVisibleChange(1f)
.setStartValue(mSpringTransY)
- .setEndValue(0)
- .setStartVelocity(mVelocity)
+ .setEndValue(endTransY)
+ .setStartVelocity(springVelocity)
.build(v, VIEW_TRANSLATE_Y);
springTransY.setStartDelay(startDelay);
springTransY.addListener(new AnimatorListenerAdapter() {
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 c9ed498..64ae1e0 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
@@ -15,6 +15,7 @@
*/
package com.android.quickstep.util;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.states.RotationHelper.deltaRotation;
import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
@@ -197,6 +198,15 @@
return mTempRectF;
}
+ /**
+ * Returns the current task bounds in the Launcher coordinate space.
+ */
+ public RectF getCurrentRect() {
+ RectF result = getCurrentCropRect();
+ mMatrix.mapRect(result);
+ return result;
+ }
+
public RecentsOrientedState getOrientationState() {
return mOrientationState;
}
@@ -295,6 +305,10 @@
builder.withMatrix(mMatrix)
.withWindowCrop(mTmpCropRect)
.withCornerRadius(getCurrentCornerRadius());
+
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.getRecentsSurface() != null) {
+ builder.withRelativeLayerTo(params.getRecentsSurface(), Integer.MAX_VALUE);
+ }
}
/**
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
index 0135f74..756331d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
@@ -16,6 +16,7 @@
package com.android.quickstep.util;
import android.util.FloatProperty;
+import android.view.SurfaceControl;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
@@ -58,6 +59,7 @@
private float mCornerRadius;
private RemoteAnimationTargets mTargetSet;
private SurfaceTransactionApplier mSyncTransactionApplier;
+ private SurfaceControl mRecentsSurface;
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
private BuilderProxy mBaseBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
@@ -138,6 +140,8 @@
public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
RemoteAnimationTargets targets = mTargetSet;
SurfaceParams[] surfaceParams = new SurfaceParams[targets.unfilteredApps.length];
+ mRecentsSurface = getRecentsSurface(targets);
+
for (int i = 0; i < targets.unfilteredApps.length; i++) {
RemoteAnimationTargetCompat app = targets.unfilteredApps[i];
SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
@@ -165,6 +169,20 @@
return surfaceParams;
}
+ private static SurfaceControl getRecentsSurface(RemoteAnimationTargets targets) {
+ for (int i = 0; i < targets.unfilteredApps.length; i++) {
+ RemoteAnimationTargetCompat app = targets.unfilteredApps[i];
+ if (app.mode == targets.targetMode) {
+ if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_RECENTS) {
+ return app.leash.getSurfaceControl();
+ }
+ } else {
+ return app.leash.getSurfaceControl();
+ }
+ }
+ return null;
+ }
+
// Pubic getters so outside packages can read the values.
public float getProgress() {
@@ -179,6 +197,10 @@
return mCornerRadius;
}
+ public SurfaceControl getRecentsSurface() {
+ return mRecentsSurface;
+ }
+
public RemoteAnimationTargets getTargetSet() {
return mTargetSet;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java
index 0979c07..3d44eb6 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java
@@ -16,6 +16,7 @@
package com.android.quickstep.views;
import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -42,8 +43,10 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.Themes;
@@ -139,7 +142,12 @@
config.userControlled = false;
AnimatorPlaybackController stateAnimationController =
mLauncher.getStateManager().createAnimationToNewWorkspace(ALL_APPS, config);
- float maxAllAppsProgress = 0.15f;
+ float maxAllAppsProgress = mLauncher.getDeviceProfile().isLandscape ? 0.35f : 0.15f;
+
+ AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
+ PendingAnimation allAppsAlpha = new PendingAnimation(config.duration);
+ allAppsController.setAlphas(ALL_APPS, config, allAppsAlpha);
+ mAnimation.play(allAppsAlpha.buildAnim());
ValueAnimator intro = ValueAnimator.ofFloat(0, 1f);
intro.setInterpolator(LINEAR);
@@ -191,7 +199,8 @@
@Override
public void onAnimationEnd(Animator animation) {
mAnimation = null;
- stateAnimationController.dispatchOnCancel();
+ // Handles cancelling the animation used to hint towards All Apps.
+ mLauncher.getStateManager().goToState(NORMAL, false);
handleClose(false);
}
});
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index 846b944..59c6815 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -41,8 +41,6 @@
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.appprediction.PredictionUiStateManager;
-import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager.StateListener;
@@ -237,9 +235,6 @@
super.reset();
setLayoutRotation(Surface.ROTATION_0, Surface.ROTATION_0);
- // We are moving to home or some other UI with no recents. Switch back to the home client,
- // the home predictions should have been updated when the activity was resumed.
- PredictionUiStateManager.INSTANCE.get(getContext()).switchClient(Client.HOME);
}
@Override
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 7b24b03..9c25b24 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
@@ -56,6 +56,7 @@
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -135,6 +136,7 @@
import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.LauncherEventUtil;
@@ -147,7 +149,7 @@
/**
* A list of recent tasks.
*/
-@TargetApi(Build.VERSION_CODES.P)
+@TargetApi(Build.VERSION_CODES.R)
public abstract class RecentsView<T extends StatefulActivity> extends PagedView implements
Insettable, TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
InvariantDeviceProfile.OnIDPChangeListener, TaskVisualsChangeListener,
@@ -1041,13 +1043,13 @@
/**
* Called when a gesture from an app is starting.
*/
- public void onGestureAnimationStart(int runningTaskId) {
+ public void onGestureAnimationStart(RunningTaskInfo runningTaskInfo) {
// This needs to be called before the other states are set since it can create the task view
if (mOrientationState.setGestureActive(true)) {
updateOrientationHandler();
}
- showCurrentTask(runningTaskId);
+ showCurrentTask(runningTaskInfo);
setEnableFreeScroll(false);
setEnableDrawingLiveTile(false);
setRunningTaskHidden(true);
@@ -1127,8 +1129,8 @@
/**
* Returns true if we should add a dummy taskView for the running task id
*/
- protected boolean shouldAddDummyTaskView(int runningTaskId) {
- return getTaskView(runningTaskId) == null;
+ protected boolean shouldAddDummyTaskView(RunningTaskInfo runningTaskInfo) {
+ return runningTaskInfo != null && getTaskView(runningTaskInfo.taskId) == null;
}
/**
@@ -1137,8 +1139,8 @@
* All subsequent calls to reload will keep the task as the first item until {@link #reset()}
* is called. Also scrolls the view to this task.
*/
- public void showCurrentTask(int runningTaskId) {
- if (shouldAddDummyTaskView(runningTaskId)) {
+ public void showCurrentTask(RunningTaskInfo runningTaskInfo) {
+ if (shouldAddDummyTaskView(runningTaskInfo)) {
boolean wasEmpty = getChildCount() == 0;
// Add an empty view for now until the task plan is loaded and applied
final TaskView taskView = mTaskViewPool.getView();
@@ -1148,10 +1150,7 @@
}
// The temporary running task is only used for the duration between the start of the
// gesture and the task list is loaded and applied
- mTmpRunningTask = new Task(new Task.TaskKey(runningTaskId, 0, new Intent(),
- new ComponentName(getContext(), getClass()), 0, 0), null, null, "", "", 0, 0,
- false, true, false, false, new ActivityManager.TaskDescription(), 0,
- new ComponentName("", ""), false);
+ mTmpRunningTask = Task.from(new TaskKey(runningTaskInfo), runningTaskInfo, false);
taskView.bind(mTmpRunningTask, mOrientationState);
// Measure and layout immediately so that the scroll values is updated instantly
@@ -1162,7 +1161,7 @@
}
boolean runningTaskTileHidden = mRunningTaskTileHidden;
- setCurrentTask(runningTaskId);
+ setCurrentTask(runningTaskInfo == null ? -1 : runningTaskInfo.taskId);
setCurrentPage(getRunningTaskIndex());
setRunningTaskViewShowScreenshot(false);
setRunningTaskHidden(runningTaskTileHidden);
@@ -1680,7 +1679,7 @@
: View.LAYOUT_DIRECTION_RTL);
mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
mActivity.getDragLayer().recreateControllers();
- boolean isInLandscape = mOrientationState.getTouchRotation() != 0
+ boolean isInLandscape = mOrientationState.getTouchRotation() != ROTATION_0
|| mOrientationState.getRecentsActivityRotation() != ROTATION_0;
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
!mOrientationState.canRecentsActivityRotate() && isInLandscape);
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 9d70316..6737c5f 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -76,6 +76,10 @@
<dimen name="gestures_assistant_drag_threshold">55dp</dimen>
<dimen name="gestures_assistant_fling_threshold">55dp</dimen>
+ <!-- One-Handed Mode -->
+ <!-- Threshold for draging distance to enable one-handed mode -->
+ <dimen name="gestures_onehanded_drag_threshold">20dp</dimen>
+
<!-- Distance to move elements when swiping up to go home from launcher -->
<dimen name="home_pullback_distance">28dp</dimen>
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java
index 93b64e6..c148a4b 100644
--- a/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.util.LauncherUIHelper.doLayout;
+import android.app.ActivityManager.RunningTaskInfo;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
@@ -50,7 +51,7 @@
}
@Test
- public void testRecets_showCurrentTask() {
+ public void testRecents_showCurrentTask() {
ActivityController<RecentsActivity> controller =
Robolectric.buildActivity(RecentsActivity.class);
@@ -58,7 +59,10 @@
doLayout(activity);
FallbackRecentsView frv = activity.getOverviewPanel();
- frv.showCurrentTask(22);
+
+ RunningTaskInfo dummyTask = new RunningTaskInfo();
+ dummyTask.taskId = 22;
+ frv.showCurrentTask(dummyTask);
doLayout(activity);
ThumbnailData thumbnailData = new ThumbnailData();
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 47ce320..6b941be 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -157,6 +157,12 @@
@Override
protected void onDeferredResumed() {
super.onDeferredResumed();
+ handlePendingActivityRequest();
+ }
+
+ @Override
+ protected void handlePendingActivityRequest() {
+ super.handlePendingActivityRequest();
if (mPendingActivityRequestCode != -1 && isInState(NORMAL)) {
// Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher.
onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null);
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 10f789d..2d096d1 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -16,8 +16,6 @@
package com.android.launcher3;
-import static android.util.TypedValue.COMPLEX_UNIT_DIP;
-
import static com.android.launcher3.BaseActivity.INVISIBLE_ALL;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
@@ -62,7 +60,6 @@
import android.os.Handler;
import android.os.Looper;
import android.util.Pair;
-import android.util.TypedValue;
import android.view.View;
import androidx.annotation.NonNull;
@@ -879,10 +876,8 @@
}
});
} else {
- float velocityDpPerS = DynamicResource.provider(mLauncher)
+ float velocityPxPerS = DynamicResource.provider(mLauncher)
.getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
- float velocityPxPerS = TypedValue.applyDimension(COMPLEX_UNIT_DIP,
- velocityDpPerS, mLauncher.getResources().getDisplayMetrics());
anim.play(new StaggeredWorkspaceAnim(mLauncher, velocityPxPerS, false)
.getAnimators());
}
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 2b698bd..bdeb3a6 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -154,13 +154,6 @@
Runnable exitRunnable);
/**
- * Updates the prediction state to the overview state.
- */
- public void updateOverviewPredictionState() {
- // By public overview predictions are not supported
- }
-
- /**
* Used for containerType in {@link com.android.launcher3.logging.UserEventDispatcher}
*/
public abstract int getContainerType();
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index ec720d5..67711c0 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -35,6 +35,7 @@
int TYPE_RESET_GESTURE = 1 << 8;
int TYPE_OVERSCROLL = 1 << 9;
int TYPE_SYSUI_OVERLAY = 1 << 10;
+ int TYPE_ONE_HANDED = 1 << 11;
String[] NAMES = new String[] {
"TYPE_NO_OP", // 0
@@ -47,7 +48,8 @@
"TYPE_OVERVIEW_WITHOUT_FOCUS", // 7
"TYPE_RESET_GESTURE", // 8
"TYPE_OVERSCROLL", // 9
- "TYPE_SYSUI_OVERLAY" // 10
+ "TYPE_SYSUI_OVERLAY", // 10
+ "TYPE_ONE_HANDED", // 11
};
InputConsumer NO_OP = () -> TYPE_NO_OP;
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 1081548..0710a0a 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -63,7 +63,9 @@
private SparseArray<OrientationRectF> mSwipeTouchRegions = new SparseArray<>(MAX_ORIENTATIONS);
private final RectF mAssistantLeftRegion = new RectF();
private final RectF mAssistantRightRegion = new RectF();
+ private final RectF mOneHandedModeRegion = new RectF();
private int mCurrentDisplayRotation;
+ private int mNavBarGesturalHeight;
private boolean mEnableMultipleRegions;
private Resources mResources;
private OrientationRectF mLastRectTouched;
@@ -103,18 +105,33 @@
mResources = resources;
mMode = mode;
mContractInfo = contractInfo;
+ mNavBarGesturalHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
}
- void setNavigationMode(SysUINavigationMode.Mode newMode, DefaultDisplay.Info info) {
+ private void refreshTouchRegion(DefaultDisplay.Info info, Resources newRes) {
+ // Swipe touch regions are independent of nav mode, so we have to clear them explicitly
+ // here to avoid, for ex, a nav region for 2-button rotation 0 being used for 3-button mode
+ // It tries to cache and reuse swipe regions whenever possible based only on rotation
+ mResources = newRes;
+ mSwipeTouchRegions.clear();
+ resetSwipeRegions(info);
+ }
+
+ void setNavigationMode(SysUINavigationMode.Mode newMode, DefaultDisplay.Info info,
+ Resources newRes) {
if (mMode == newMode) {
return;
}
this.mMode = newMode;
- // Swipe touch regions are independent of nav mode, so we have to clear them explicitly
- // here to avoid, for ex, a nav region for 2-button rotation 0 being used for 3-button mode
- // It tries to cache and reuse swipe regions whenever possible based only on rotation
- mSwipeTouchRegions.clear();
- resetSwipeRegions(info);
+ refreshTouchRegion(info, newRes);
+ }
+
+ void setGesturalHeight(int newGesturalHeight, DefaultDisplay.Info info, Resources newRes) {
+ if (mNavBarGesturalHeight == newGesturalHeight) {
+ return;
+ }
+ mNavBarGesturalHeight = newGesturalHeight;
+ refreshTouchRegion(info, newRes);
}
/**
@@ -216,10 +233,10 @@
Point size = display.realSize;
int rotation = display.rotation;
+ int touchHeight = mNavBarGesturalHeight;
OrientationRectF orientationRectF =
new OrientationRectF(0, 0, size.x, size.y, rotation);
if (mMode == SysUINavigationMode.Mode.NO_BUTTON) {
- int touchHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
orientationRectF.top = orientationRectF.bottom - touchHeight;
updateAssistantRegions(orientationRectF);
} else {
@@ -235,10 +252,11 @@
+ getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
break;
default:
- orientationRectF.top = orientationRectF.bottom
- - getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
+ orientationRectF.top = orientationRectF.bottom - touchHeight;
}
}
+ // One handed gestural only active on portrait mode
+ mOneHandedModeRegion.set(0, orientationRectF.bottom - touchHeight, size.x, size.y);
return orientationRectF;
}
@@ -264,6 +282,10 @@
}
+ boolean touchInOneHandedModeRegion(MotionEvent ev) {
+ return mOneHandedModeRegion.contains(ev.getX(), ev.getY());
+ }
+
private int getNavbarSize(String resName) {
return ResourceUtils.getNavbarSize(resName, mResources);
}
@@ -355,6 +377,8 @@
regions.append(rectF.mRotation).append(" ");
}
pw.println(regions.toString());
+ pw.println(" mNavBarGesturalHeight=" + mNavBarGesturalHeight);
+ pw.println(" mOneHandedModeRegion=" + mOneHandedModeRegion);
}
private class OrientationRectF extends RectF {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 0a70bd6..6b0c395 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -31,6 +31,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
@@ -45,11 +46,14 @@
import android.content.res.Resources;
import android.graphics.Region;
import android.os.Process;
+import android.os.SystemProperties;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.OrientationEventListener;
+import android.view.Surface;
import androidx.annotation.BinderThread;
@@ -59,6 +63,7 @@
import com.android.launcher3.util.DefaultDisplay;
import com.android.launcher3.util.SecureSettingsObserver;
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
+import com.android.quickstep.SysUINavigationMode.OneHandedModeChangeListener;
import com.android.quickstep.util.NavBarPosition;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -77,7 +82,8 @@
*/
public class RecentsAnimationDeviceState implements
NavigationModeChangeListener,
- DefaultDisplay.DisplayInfoChangeListener {
+ DefaultDisplay.DisplayInfoChangeListener,
+ OneHandedModeChangeListener {
private final Context mContext;
private final SysUINavigationMode mSysUiNavMode;
@@ -94,6 +100,8 @@
private final Region mDeferredGestureRegion = new Region();
private boolean mAssistantAvailable;
private float mAssistantVisibility;
+ private boolean mIsOneHandedModeEnabled;
+ private boolean mIsSwipeToNotificationEnabled;
private boolean mIsUserUnlocked;
private final ArrayList<Runnable> mUserUnlockedActions = new ArrayList<>();
@@ -231,6 +239,22 @@
}
}
+ if (SystemProperties.getBoolean("ro.support_one_handed_mode", false)) {
+ SecureSettingsObserver oneHandedEnabledObserver =
+ SecureSettingsObserver.newOneHandedSettingsObserver(
+ mContext, enabled -> mIsOneHandedModeEnabled = enabled);
+ oneHandedEnabledObserver.register();
+ oneHandedEnabledObserver.dispatchOnChange();
+ runOnDestroy(oneHandedEnabledObserver::unregister);
+ }
+
+ SecureSettingsObserver swipeBottomEnabledObserver =
+ SecureSettingsObserver.newSwipeToNotificationSettingsObserver(
+ mContext, enabled -> mIsSwipeToNotificationEnabled = enabled);
+ swipeBottomEnabledObserver.register();
+ swipeBottomEnabledObserver.dispatchOnChange();
+ runOnDestroy(swipeBottomEnabledObserver::unregister);
+
SecureSettingsObserver userSetupObserver = new SecureSettingsObserver(
context.getContentResolver(),
e -> mIsUserSetupComplete = e,
@@ -297,6 +321,15 @@
runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(listener));
}
+ /**
+ * Adds a listener for the one handed mode change,
+ * guaranteed to be called after the device state's mode has changed.
+ */
+ public void addOneHandedModeChangedCallback(OneHandedModeChangeListener listener) {
+ listener.onOneHandedModeChanged(mSysUiNavMode.addOneHandedOverlayChangeListener(listener));
+ runOnDestroy(() -> mSysUiNavMode.removeOneHandedOverlayChangeListener(listener));
+ }
+
@Override
public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
mDefaultDisplay.removeChangeListener(this);
@@ -311,7 +344,8 @@
mNavBarPosition = new NavBarPosition(newMode, mDefaultDisplay.getInfo());
- mOrientationTouchTransformer.setNavigationMode(newMode, mDefaultDisplay.getInfo());
+ mOrientationTouchTransformer.setNavigationMode(newMode, mDefaultDisplay.getInfo(),
+ mContext.getApplicationContext().getResources());
if (!mMode.hasGestures && newMode.hasGestures) {
setupOrientationSwipeHandler();
} else if (mMode.hasGestures && !newMode.hasGestures){
@@ -352,6 +386,12 @@
}
}
+ @Override
+ public void onOneHandedModeChanged(int newGesturalHeight) {
+ mOrientationTouchTransformer.setGesturalHeight(newGesturalHeight, mDefaultDisplay.getInfo(),
+ mContext.getApplicationContext().getResources());
+ }
+
/**
* @return the current navigation mode for the device.
*/
@@ -564,6 +604,13 @@
}
/**
+ * @return whether screen pinning is enabled and active
+ */
+ public boolean isOneHandedModeActive() {
+ return (mSystemUiStateFlags & SYSUI_STATE_ONE_HANDED_ACTIVE) != 0;
+ }
+
+ /**
* Sets the region in screen space where the gestures should be deferred (ie. due to specific
* nav bar ui).
*/
@@ -626,6 +673,32 @@
}
/**
+ * One handed gestural in quickstep only active on NO_BUTTON, TWO_BUTTONS, and portrait mode
+ *
+ * @param ev The touch screen motion event.
+ * @return whether the given motion event can trigger the one handed mode.
+ */
+ public boolean canTriggerOneHandedAction(MotionEvent ev) {
+ if (!mIsOneHandedModeEnabled && !mIsSwipeToNotificationEnabled) {
+ return false;
+ }
+
+ final DefaultDisplay.Info displayInfo = mDefaultDisplay.getInfo();
+ return (mOrientationTouchTransformer.touchInOneHandedModeRegion(ev)
+ && displayInfo.rotation != Surface.ROTATION_90
+ && displayInfo.rotation != Surface.ROTATION_270
+ && displayInfo.metrics.densityDpi < DisplayMetrics.DENSITY_600);
+ }
+
+ public boolean isOneHandedModeEnabled() {
+ return mIsOneHandedModeEnabled;
+ }
+
+ public boolean isSwipeToNotificationEnabled() {
+ return mIsSwipeToNotificationEnabled;
+ }
+
+ /**
* *May* apply a transform on the motion event if it lies in the nav bar region for another
* orientation that is currently being tracked as a part of quickstep
*/
@@ -729,6 +802,8 @@
pw.println(" currentActiveRotation=" + getCurrentActiveRotation());
pw.println(" displayRotation=" + getDisplayRotation());
pw.println(" isUserUnlocked=" + mIsUserUnlocked);
+ pw.println(" isOneHandedModeEnabled=" + mIsOneHandedModeEnabled);
+ pw.println(" isSwipeToNotificationEnabled=" + mIsSwipeToNotificationEnabled);
mOrientationTouchTransformer.dump(pw);
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 517501a..6f54ba2 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -93,15 +93,6 @@
}
/**
- * @return The task id of the running task, or -1 if there is no current running task.
- */
- public static int getRunningTaskId() {
- ActivityManager.RunningTaskInfo runningTask =
- ActivityManagerWrapper.getInstance().getRunningTask();
- return runningTask != null ? runningTask.id : -1;
- }
-
- /**
* @return Whether the provided {@param changeId} is the latest recent tasks list id.
*/
public boolean isTaskListValid(int changeId) {
@@ -140,7 +131,9 @@
}
// Keep the cache up to date with the latest thumbnails
- int runningTaskId = RecentsModel.getRunningTaskId();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
+ int runningTaskId = runningTask != null ? runningTask.id : -1;
mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), tasks -> {
for (Task task : tasks) {
if (task.key.id == runningTaskId) {
diff --git a/quickstep/src/com/android/quickstep/SysUINavigationMode.java b/quickstep/src/com/android/quickstep/SysUINavigationMode.java
index 05ce2a2..6994d66 100644
--- a/quickstep/src/com/android/quickstep/SysUINavigationMode.java
+++ b/quickstep/src/com/android/quickstep/SysUINavigationMode.java
@@ -16,14 +16,15 @@
package com.android.quickstep;
+import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Resources;
import android.util.Log;
+import com.android.launcher3.ResourceUtils;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.MainThreadInitializedObject;
@@ -58,15 +59,19 @@
new MainThreadInitializedObject<>(SysUINavigationMode::new);
private static final String TAG = "SysUINavigationMode";
-
private static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED";
private static final String NAV_BAR_INTERACTION_MODE_RES_NAME =
"config_navBarInteractionMode";
+ private static final String TARGET_OVERLAY_PACKAGE = "android";
private final Context mContext;
private Mode mMode;
+ private int mNavBarGesturalHeight;
+
private final List<NavigationModeChangeListener> mChangeListeners = new ArrayList<>();
+ private final List<OneHandedModeChangeListener> mOneHandedOverlayChangeListeners =
+ new ArrayList<>();
public SysUINavigationMode(Context context) {
mContext = context;
@@ -76,8 +81,9 @@
@Override
public void onReceive(Context context, Intent intent) {
updateMode();
+ updateGesturalHeight();
}
- }, getPackageFilter("android", ACTION_OVERLAY_CHANGED));
+ }, getPackageFilter(TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED));
}
/** Updates navigation mode when needed. */
@@ -89,9 +95,35 @@
}
}
+ private void updateGesturalHeight() {
+ int newGesturalHeight = ResourceUtils.getDimenByName(
+ ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mContext.getResources(),
+ INVALID_RESOURCE_HANDLE);
+
+ if (newGesturalHeight == INVALID_RESOURCE_HANDLE) {
+ Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
+ return;
+ }
+
+ if (mNavBarGesturalHeight != newGesturalHeight) {
+ mNavBarGesturalHeight = newGesturalHeight;
+ dispatchOneHandedOverlayChange();
+ }
+ }
+
private void initializeMode() {
- int modeInt = getSystemIntegerRes(mContext, NAV_BAR_INTERACTION_MODE_RES_NAME);
- for(Mode m : Mode.values()) {
+ int modeInt = ResourceUtils.getIntegerByName(NAV_BAR_INTERACTION_MODE_RES_NAME,
+ mContext.getResources(), INVALID_RESOURCE_HANDLE);
+ mNavBarGesturalHeight = ResourceUtils.getDimenByName(
+ ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mContext.getResources(),
+ INVALID_RESOURCE_HANDLE);
+
+ if (modeInt == INVALID_RESOURCE_HANDLE) {
+ Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
+ return;
+ }
+
+ for (Mode m : Mode.values()) {
if (m.resValue == modeInt) {
mMode = m;
}
@@ -104,6 +136,12 @@
}
}
+ private void dispatchOneHandedOverlayChange() {
+ for (OneHandedModeChangeListener listener : mOneHandedOverlayChangeListeners) {
+ listener.onOneHandedModeChanged(mNavBarGesturalHeight);
+ }
+ }
+
public Mode addModeChangeListener(NavigationModeChangeListener listener) {
mChangeListeners.add(listener);
return mMode;
@@ -113,20 +151,17 @@
mChangeListeners.remove(listener);
}
- public Mode getMode() {
- return mMode;
+ public int addOneHandedOverlayChangeListener(OneHandedModeChangeListener listener) {
+ mOneHandedOverlayChangeListeners.add(listener);
+ return mNavBarGesturalHeight;
}
- private static int getSystemIntegerRes(Context context, String resName) {
- Resources res = context.getResources();
- int resId = res.getIdentifier(resName, "integer", "android");
+ public void removeOneHandedOverlayChangeListener(OneHandedModeChangeListener listener) {
+ mOneHandedOverlayChangeListeners.remove(listener);
+ }
- if (resId != 0) {
- return res.getInteger(resId);
- } else {
- Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
- return -1;
- }
+ public Mode getMode() {
+ return mMode;
}
/** @return Whether we can remove the shelf from overview. */
@@ -144,10 +179,16 @@
public void dump(PrintWriter pw) {
pw.println("SysUINavigationMode:");
pw.println(" mode=" + mMode.name());
+ pw.println(" mNavBarGesturalHeight=:" + mNavBarGesturalHeight);
}
public interface NavigationModeChangeListener {
void onNavigationModeChanged(Mode newMode);
}
+
+ public interface OneHandedModeChangeListener {
+
+ void onOneHandedModeChanged(int newGesturalHeight);
+ }
}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 299e9e5..5b239a4 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -347,6 +347,28 @@
}
@Override
+ public void startOneHandedMode() {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.startOneHandedMode();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call startOneHandedMode", e);
+ }
+ }
+ }
+
+ @Override
+ public void stopOneHandedMode() {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.stopOneHandedMode();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call stopOneHandedMode", e);
+ }
+ }
+ }
+
+ @Override
public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
Insets visibleInsets, Task.TaskKey task) {
if (mSystemUiProxy != null) {
@@ -358,4 +380,15 @@
}
}
}
+
+ @Override
+ public void expandNotificationPanel() {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.expandNotificationPanel();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call expandNotificationPanel", e);
+ }
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index ae19d73..f7bd1e2 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -49,7 +49,7 @@
Rect taskSize = new Rect();
LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
orientationHandler);
- return (dp.heightPx - taskSize.height()) / 2;
+ return orientationHandler.getDistanceToBottomOfRect(dp, taskSize);
}
int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
int spaceBetweenShelfAndRecents = (int) context.getResources().getDimension(
diff --git a/res/layout/launcher_preview_layout.xml b/res/layout/launcher_preview_layout.xml
index 3fd02e3..4a20c70 100644
--- a/res/layout/launcher_preview_layout.xml
+++ b/res/layout/launcher_preview_layout.xml
@@ -17,7 +17,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:focusable="false">
<com.android.launcher3.CellLayout
android:id="@+id/workspace"
diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml
deleted file mode 100644
index 0758148..0000000
--- a/res/values-rm/strings.xml
+++ /dev/null
@@ -1,203 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/*
-* Copyright (C) 2008 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.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for application_name (5181331383435256801) -->
- <skip />
- <!-- no translation found for home (7658288663002113681) -->
- <skip />
- <!-- no translation found for uid_name (7820867637514617527) -->
- <skip />
- <string name="folder_name" msgid="7371454440695724752"></string>
- <!-- no translation found for activity_not_found (8071924732094499514) -->
- <skip />
- <!-- no translation found for widgets_tab_label (2921133187116603919) -->
- <skip />
- <!-- no translation found for widget_adder (3201040140710381657) -->
- <skip />
- <!-- no translation found for toggle_weight_watcher (5645299835184636119) -->
- <skip />
- <!-- no translation found for long_press_widget_to_add (7699152356777458215) -->
- <skip />
- <!-- no translation found for market (2619650989819296998) -->
- <skip />
- <!-- no translation found for widget_dims_format (2370757736025621599) -->
- <skip />
- <!-- no translation found for external_drop_widget_error (3165821058322217155) -->
- <skip />
- <!-- no translation found for external_drop_widget_pick_title (3486317258037690630) -->
- <skip />
- <!-- no translation found for rename_folder_label (3727762225964550653) -->
- <skip />
- <!-- no translation found for rename_folder_title (3771389277707820891) -->
- <skip />
- <!-- no translation found for rename_action (5559600076028658757) -->
- <skip />
- <!-- no translation found for cancel_action (7009134900002915310) -->
- <skip />
- <!-- no translation found for menu_item_add_item (1264911265836810421) -->
- <skip />
- <!-- no translation found for group_applications (3797214114206693605) -->
- <skip />
- <!-- no translation found for group_shortcuts (6012256992764410535) -->
- <skip />
- <!-- no translation found for group_widgets (1569030723286851002) -->
- <skip />
- <!-- no translation found for completely_out_of_space (6106288382070760318) -->
- <skip />
- <!-- no translation found for out_of_space (4691004494942118364) -->
- <skip />
- <!-- no translation found for hotseat_out_of_space (7448809638125333693) -->
- <skip />
- <!-- no translation found for invalid_hotseat_item (5779907847267573691) -->
- <skip />
- <!-- no translation found for shortcut_installed (1701742129426969556) -->
- <skip />
- <!-- no translation found for shortcut_uninstalled (8176767991305701821) -->
- <skip />
- <!-- no translation found for shortcut_duplicate (9167217446062498127) -->
- <skip />
- <!-- no translation found for title_select_shortcut (6680642571148153868) -->
- <skip />
- <!-- no translation found for title_select_application (3280812711670683644) -->
- <skip />
- <!-- no translation found for all_apps_button_label (9110807029020582876) -->
- <skip />
- <!-- no translation found for all_apps_home_button_label (252062713717058851) -->
- <skip />
- <!-- no translation found for delete_zone_label_workspace (4009607676751398685) -->
- <skip />
- <!-- no translation found for delete_zone_label_all_apps (8083826390278958980) -->
- <skip />
- <!-- no translation found for delete_target_label (1822697352535677073) -->
- <skip />
- <!-- no translation found for delete_target_uninstall_label (5100785476250872595) -->
- <skip />
- <!-- no translation found for info_target_label (8053346143994679532) -->
- <skip />
- <!-- no translation found for accessibility_search_button (1628520399424565142) -->
- <skip />
- <!-- no translation found for accessibility_voice_search_button (4637324840434406584) -->
- <skip />
- <!-- no translation found for accessibility_all_apps_button (2603132375383800483) -->
- <skip />
- <!-- no translation found for accessibility_delete_button (6466114477993744621) -->
- <skip />
- <!-- no translation found for delete_zone_label_all_apps_system_app (449755632749610895) -->
- <skip />
- <!-- no translation found for cab_menu_delete_app (7435191475867183689) -->
- <skip />
- <!-- no translation found for cab_menu_app_info (8593722221450362342) -->
- <skip />
- <!-- no translation found for cab_app_selection_text (374688303047985416) -->
- <skip />
- <!-- no translation found for cab_widget_selection_text (1833458597831541241) -->
- <skip />
- <!-- no translation found for cab_folder_selection_text (7999992513806132118) -->
- <skip />
- <!-- no translation found for cab_shortcut_selection_text (2103811025667946450) -->
- <skip />
- <!-- no translation found for permlab_install_shortcut (5632423390354674437) -->
- <skip />
- <!-- no translation found for permdesc_install_shortcut (923466509822011139) -->
- <skip />
- <!-- no translation found for permlab_uninstall_shortcut (864595034498083837) -->
- <skip />
- <!-- no translation found for permdesc_uninstall_shortcut (5134129545001836849) -->
- <skip />
- <!-- no translation found for permlab_read_settings (1941457408239617576) -->
- <skip />
- <!-- no translation found for permdesc_read_settings (5833423719057558387) -->
- <skip />
- <!-- no translation found for permlab_write_settings (3574213698004620587) -->
- <skip />
- <!-- no translation found for permdesc_write_settings (5440712911516509985) -->
- <skip />
- <!-- no translation found for gadget_error_text (6081085226050792095) -->
- <skip />
- <!-- no translation found for uninstall_system_app_text (4172046090762920660) -->
- <skip />
- <!-- no translation found for dream_name (1530253749244328964) -->
- <skip />
- <!-- no translation found for folder_hint_text (6617836969016293992) -->
- <skip />
- <!-- no translation found for workspace_description_format (2950174241104043327) -->
- <skip />
- <!-- no translation found for default_scroll_format (7475544710230993317) -->
- <skip />
- <!-- no translation found for workspace_scroll_format (8458889198184077399) -->
- <skip />
- <!-- no translation found for apps_customize_apps_scroll_format (370005296147130238) -->
- <skip />
- <!-- no translation found for apps_customize_widgets_scroll_format (3106209519974971521) -->
- <skip />
- <!-- no translation found for first_run_cling_title (2459738000155917941) -->
- <skip />
- <!-- no translation found for first_run_cling_description (6447072552696253358) -->
- <skip />
- <!-- no translation found for first_run_cling_create_screens_hint (6950729526680114157) -->
- <skip />
- <!-- no translation found for migration_cling_title (9181776667882933767) -->
- <skip />
- <!-- no translation found for migration_cling_description (2752413805582227644) -->
- <skip />
- <!-- no translation found for migration_cling_copy_apps (946331230090919440) -->
- <skip />
- <!-- no translation found for migration_cling_use_default (2626475813981258626) -->
- <skip />
- <!-- no translation found for workspace_cling_title (5626202359865825661) -->
- <skip />
- <!-- no translation found for workspace_cling_move_item (528201129978005352) -->
- <skip />
- <!-- no translation found for folder_cling_title (3894908818693254164) -->
- <skip />
- <!-- no translation found for folder_cling_create_folder (6158215559475836131) -->
- <skip />
- <!-- no translation found for cling_dismiss (8962359497601507581) -->
- <skip />
- <!-- no translation found for folder_opened (94695026776264709) -->
- <skip />
- <!-- no translation found for folder_tap_to_close (1884479294466410023) -->
- <skip />
- <!-- no translation found for folder_tap_to_rename (9191075570492871147) -->
- <skip />
- <!-- no translation found for folder_closed (4100806530910930934) -->
- <skip />
- <!-- no translation found for folder_renamed (1794088362165669656) -->
- <skip />
- <!-- no translation found for folder_name_format (6629239338071103179) -->
- <skip />
- <!-- no translation found for widget_button_text (2880537293434387943) -->
- <skip />
- <!-- no translation found for wallpaper_button_text (8404103075899945851) -->
- <skip />
- <!-- no translation found for settings_button_text (8119458837558863227) -->
- <skip />
- <!-- no translation found for package_state_enqueued (6227252464303085641) -->
- <skip />
- <!-- no translation found for package_state_downloading (4088770468458724721) -->
- <skip />
- <!-- no translation found for package_state_installing (7588193972189849870) -->
- <skip />
- <!-- no translation found for package_state_unknown (7592128424511031410) -->
- <skip />
- <!-- no translation found for package_state_error (7672093962724223588) -->
- <skip />
-</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index ca25325..75fcc90 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -142,7 +142,7 @@
<item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
<item name="staggered_stiffness" type="dimen" format="float">150</item>
- <dimen name="unlock_staggered_velocity_dp_per_s">3dp</dimen>
+ <dimen name="unlock_staggered_velocity_dp_per_s">4dp</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>
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index 8eceec0..41eeb78 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -183,6 +183,10 @@
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onScrollStateChanged: " + state);
+ }
+
if (state == SCROLL_STATE_IDLE) {
AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
}
@@ -192,6 +196,10 @@
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
if (isLayoutSuppressed()) info.setScrollable(false);
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS,
+ "onInitializeAccessibilityNodeInfo, scrollable: " + info.isScrollable());
+ }
}
@Override
@@ -199,8 +207,12 @@
final boolean changing = frozen != isLayoutSuppressed();
super.setLayoutFrozen(frozen);
if (changing) {
- ActivityContext.lookupContext(getContext()).getDragLayer()
- .sendAccessibilityEvent(TYPE_WINDOW_CONTENT_CHANGED);
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "setLayoutFrozen " + frozen
+ + " @ " + Log.getStackTraceString(new Throwable()));
+ ActivityContext.lookupContext(getContext()).getDragLayer()
+ .sendAccessibilityEvent(TYPE_WINDOW_CONTENT_CHANGED);
+ }
}
}
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0970dae..d06ae7a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -923,6 +923,7 @@
DiscoveryBounce.showForHomeIfNeeded(this);
}
+ protected void handlePendingActivityRequest() { }
private void logStopAndResume(int command) {
int pageIndex = mWorkspace.isOverlayShown() ? -1 : mWorkspace.getCurrentPage();
@@ -1423,7 +1424,8 @@
if (!isInState(NORMAL)) {
// Only change state, if not already the same. This prevents cancelling any
// animations running as part of resume
- mStateManager.goToState(NORMAL);
+ mStateManager.goToState(NORMAL, mStateManager.shouldAnimateStateChange(),
+ this::handlePendingActivityRequest);
}
// Reset the apps view
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index f434c91..ff4b545 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -58,7 +58,7 @@
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutRequest;
-import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.PackageUserKey;
@@ -410,7 +410,7 @@
enqueueModelUpdateTask(new BaseModelUpdateTask() {
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
- final IntSparseArrayMap<Boolean> removedIds = new IntSparseArrayMap<>();
+ final IntSet removedIds = new IntSet();
synchronized (dataModel) {
for (ItemInfo info : dataModel.itemsIdMap) {
if (info instanceof WorkspaceItemInfo
@@ -418,13 +418,13 @@
&& user.equals(info.user)
&& info.getIntent() != null
&& TextUtils.equals(packageName, info.getIntent().getPackage())) {
- removedIds.put(info.id, true /* remove */);
+ removedIds.add(info.id);
}
}
}
if (!removedIds.isEmpty()) {
- deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedIds, false));
+ deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedIds));
}
}
});
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index c78df62..39b0f2f 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -250,7 +250,8 @@
}
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
- if (this != NORMAL || !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
+ if ((this != NORMAL && this != HINT_STATE)
+ || !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
return DEFAULT_ALPHA_PROVIDER;
}
final int centerPage = launcher.getWorkspace().getNextPage();
diff --git a/src/com/android/launcher3/ResourceUtils.java b/src/com/android/launcher3/ResourceUtils.java
index 403d779..c9fb75a 100644
--- a/src/com/android/launcher3/ResourceUtils.java
+++ b/src/com/android/launcher3/ResourceUtils.java
@@ -22,6 +22,7 @@
public class ResourceUtils {
public static final int DEFAULT_NAVBAR_VALUE = 48;
+ public static final int INVALID_RESOURCE_HANDLE = -1;
public static final String NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE = "navigation_bar_width";
public static final String NAVBAR_BOTTOM_GESTURE_SIZE = "navigation_bar_gesture_height";
@@ -51,7 +52,13 @@
return val;
}
+ public static int getIntegerByName(String resName, Resources res, int defaultValue) {
+ int resId = res.getIdentifier(resName, "integer", "android");
+ return resId != 0 ? res.getInteger(resId) : defaultValue;
+ }
+
public static int pxFromDp(float size, DisplayMetrics metrics) {
- return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, metrics));
+ return size < 0 ? INVALID_RESOURCE_HANDLE : Math.round(
+ TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, metrics));
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index c989e7b..77b8a32 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -83,7 +83,7 @@
protected final BaseDraggingActivity mLauncher;
protected final AdapterHolder[] mAH;
private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle());
- private final ItemInfoMatcher mWorkMatcher = ItemInfoMatcher.not(mPersonalMatcher);
+ private final ItemInfoMatcher mWorkMatcher = mPersonalMatcher.negate();
private final AllAppsStore mAllAppsStore = new AllAppsStore();
private final Paint mNavBarScrimPaint;
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index 1d32d1d..d86bb17 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -75,6 +75,9 @@
}
public static void sendScrollFinishedEventToTest(Context context) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "sendScrollFinishedEventToTest");
+ }
final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
if (accessibilityManager == null) return;
@@ -94,6 +97,9 @@
AccessibilityEvent.TYPE_ANNOUNCEMENT);
e.setClassName(eventTag);
e.setParcelableData(data);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "sendEventToTest " + e);
+ }
accessibilityManager.sendAccessibilityEvent(e);
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index d01e189..1c18402 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -241,9 +241,9 @@
mFolderName.setSelectAllOnFocus(true);
mFolderName.setInputType(mFolderName.getInputType()
& ~InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
- & ~InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
+ | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
| InputType.TYPE_TEXT_FLAG_CAP_WORDS);
- mFolderName.forceDisableSuggestions(!FeatureFlags.FOLDER_NAME_SUGGEST.get());
+ mFolderName.forceDisableSuggestions(true);
mFooter = findViewById(R.id.folder_footer);
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 9bef847..7524920 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -56,6 +56,7 @@
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
@@ -348,6 +349,19 @@
}
}
+ /**
+ * Calls the provided {@code op} for all workspaceItems in the in-memory model (both persisted
+ * items and dynamic/predicted items for the provided {@code userHandle}.
+ * Note the call is not synchronized over the model, that should be handled by the called.
+ */
+ public void forAllWorkspaceItemInfos(UserHandle userHandle, Consumer<WorkspaceItemInfo> op) {
+ for (ItemInfo info : itemsIdMap) {
+ if (info instanceof WorkspaceItemInfo && userHandle.equals(info.user)) {
+ op.accept((WorkspaceItemInfo) info);
+ }
+ }
+ }
+
public interface Callbacks {
// If the launcher has permission to access deep shortcuts.
int FLAG_HAS_SHORTCUT_PERMISSION = 1 << 0;
diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
index 8e6b064..f644d49 100644
--- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java
+++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
@@ -21,7 +21,6 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import java.util.ArrayList;
@@ -48,23 +47,18 @@
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
IconCache iconCache = app.getIconCache();
-
-
ArrayList<WorkspaceItemInfo> updatedShortcuts = new ArrayList<>();
synchronized (dataModel) {
- for (ItemInfo info : dataModel.itemsIdMap) {
- if (info instanceof WorkspaceItemInfo && mUser.equals(info.user)) {
- WorkspaceItemInfo si = (WorkspaceItemInfo) info;
- ComponentName cn = si.getTargetComponent();
- if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
- && isValidShortcut(si) && cn != null
- && mPackages.contains(cn.getPackageName())) {
- iconCache.getTitleAndIcon(si, si.usingLowResIcon());
- updatedShortcuts.add(si);
- }
+ dataModel.forAllWorkspaceItemInfos(mUser, si -> {
+ ComponentName cn = si.getTargetComponent();
+ if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+ && isValidShortcut(si) && cn != null
+ && mPackages.contains(cn.getPackageName())) {
+ iconCache.getTitleAndIcon(si, si.usingLowResIcon());
+ updatedShortcuts.add(si);
}
- }
+ });
apps.updateIconsAndLabels(mPackages, mUser);
}
bindUpdatedWorkspaceItems(updatedShortcuts);
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index 203f1ca..8369c48 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -20,8 +20,6 @@
import android.content.pm.PackageManager;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherModel.CallbackTask;
-import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.PromiseAppInfo;
@@ -70,21 +68,18 @@
synchronized (dataModel) {
final HashSet<ItemInfo> updates = new HashSet<>();
- for (ItemInfo info : dataModel.itemsIdMap) {
- if (info instanceof WorkspaceItemInfo) {
- WorkspaceItemInfo si = (WorkspaceItemInfo) info;
- ComponentName cn = si.getTargetComponent();
- if (si.hasPromiseIconUi() && (cn != null)
- && mInstallInfo.packageName.equals(cn.getPackageName())) {
- si.setInstallProgress(mInstallInfo.progress);
- if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) {
- // Mark this info as broken.
- si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE;
- }
- updates.add(si);
+ dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> {
+ ComponentName cn = si.getTargetComponent();
+ if (si.hasPromiseIconUi() && (cn != null)
+ && mInstallInfo.packageName.equals(cn.getPackageName())) {
+ si.setInstallProgress(mInstallInfo.progress);
+ if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) {
+ // Mark this info as broken.
+ si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE;
}
+ updates.add(si);
}
- }
+ });
for (LauncherAppWidgetInfo widget : dataModel.appWidgets) {
if (widget.providerName.getPackageName().equals(mInstallInfo.packageName)) {
@@ -94,12 +89,7 @@
}
if (!updates.isEmpty()) {
- scheduleCallbackTask(new CallbackTask() {
- @Override
- public void execute(Callbacks callbacks) {
- callbacks.bindRestoreItemsChange(updates);
- }
- });
+ scheduleCallbackTask(callbacks -> callbacks.bindRestoreItemsChange(updates));
}
}
}
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 7cd467e..dca4ec0 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -45,7 +45,7 @@
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.FlagOp;
-import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
@@ -92,9 +92,11 @@
final String[] packages = mPackages;
final int N = packages.length;
- FlagOp flagOp = FlagOp.NO_OP;
+ final FlagOp flagOp;
final HashSet<String> packageSet = new HashSet<>(Arrays.asList(packages));
- ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packageSet, mUser);
+ final ItemInfoMatcher matcher = mOp == OP_USER_AVAILABILITY_CHANGE
+ ? ItemInfoMatcher.ofUser(mUser) // We want to update all packages for this user
+ : ItemInfoMatcher.ofPackages(packageSet, mUser);
final HashSet<ComponentName> removedComponents = new HashSet<>();
switch (mOp) {
@@ -158,19 +160,22 @@
flagOp = ums.isUserQuiet(mUser)
? FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER)
: FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER);
- // We want to update all packages for this user.
- matcher = ItemInfoMatcher.ofUser(mUser);
appsList.updateDisabledFlags(matcher, flagOp);
// We are not synchronizing here, as int operations are atomic
appsList.setFlags(FLAG_QUIET_MODE_ENABLED, ums.isAnyProfileQuietModeEnabled());
break;
}
+ default:
+ flagOp = FlagOp.NO_OP;
+ break;
}
bindApplicationsIfNeeded();
- final IntSparseArrayMap<Boolean> removedShortcuts = new IntSparseArrayMap<>();
+ final IntSet removedShortcuts = new IntSet();
+ // Shortcuts to keep even if the corresponding app was removed
+ final IntSet forceKeepShortcuts = new IntSet();
// Update shortcut infos
if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
@@ -180,118 +185,118 @@
// For system apps, package manager send OP_UPDATE when an app is enabled.
final boolean isNewApkAvailable = mOp == OP_ADD || mOp == OP_UPDATE;
synchronized (dataModel) {
- for (ItemInfo info : dataModel.itemsIdMap) {
- if (info instanceof WorkspaceItemInfo && mUser.equals(info.user)) {
- WorkspaceItemInfo si = (WorkspaceItemInfo) info;
- boolean infoUpdated = false;
- boolean shortcutUpdated = false;
+ dataModel.forAllWorkspaceItemInfos(mUser, si -> {
- // Update shortcuts which use iconResource.
- if ((si.iconResource != null)
- && packageSet.contains(si.iconResource.packageName)) {
- LauncherIcons li = LauncherIcons.obtain(context);
- BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
- li.recycle();
- if (iconInfo != null) {
- si.bitmap = iconInfo;
- infoUpdated = true;
+ boolean infoUpdated = false;
+ boolean shortcutUpdated = false;
+
+ // Update shortcuts which use iconResource.
+ if ((si.iconResource != null)
+ && packageSet.contains(si.iconResource.packageName)) {
+ LauncherIcons li = LauncherIcons.obtain(context);
+ BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
+ li.recycle();
+ if (iconInfo != null) {
+ si.bitmap = iconInfo;
+ infoUpdated = true;
+ }
+ }
+
+ ComponentName cn = si.getTargetComponent();
+ if (cn != null && matcher.matches(si, cn)) {
+ String packageName = cn.getPackageName();
+
+ if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)) {
+ forceKeepShortcuts.add(si.id);
+ if (mOp == OP_REMOVE) {
+ return;
}
}
- ComponentName cn = si.getTargetComponent();
- if (cn != null && matcher.matches(si, cn)) {
- String packageName = cn.getPackageName();
-
- if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)) {
- removedShortcuts.put(si.id, false);
- if (mOp == OP_REMOVE) {
- continue;
- }
- }
-
- if (si.isPromise() && isNewApkAvailable) {
- boolean isTargetValid = true;
- if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- List<ShortcutInfo> shortcut =
- new ShortcutRequest(context, mUser)
- .forPackage(cn.getPackageName(),
- si.getDeepShortcutId())
- .query(ShortcutRequest.PINNED);
- if (shortcut.isEmpty()) {
- isTargetValid = false;
- } else {
- si.updateFromDeepShortcutInfo(shortcut.get(0), context);
- infoUpdated = true;
- }
- } else if (!cn.getClassName().equals(IconCache.EMPTY_CLASS_NAME)) {
- isTargetValid = context.getSystemService(LauncherApps.class)
- .isActivityEnabled(cn, mUser);
- }
- if (si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) {
- if (updateWorkspaceItemIntent(context, si, packageName)) {
- infoUpdated = true;
- } else if (si.hasPromiseIconUi()) {
- removedShortcuts.put(si.id, true);
- continue;
- }
- } else if (!isTargetValid) {
- removedShortcuts.put(si.id, true);
- FileLog.e(TAG, "Restored shortcut no longer valid "
- + si.getIntent());
- continue;
+ if (si.isPromise() && isNewApkAvailable) {
+ boolean isTargetValid = true;
+ if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ List<ShortcutInfo> shortcut =
+ new ShortcutRequest(context, mUser)
+ .forPackage(cn.getPackageName(),
+ si.getDeepShortcutId())
+ .query(ShortcutRequest.PINNED);
+ if (shortcut.isEmpty()) {
+ isTargetValid = false;
} else {
- si.status = WorkspaceItemInfo.DEFAULT;
+ si.updateFromDeepShortcutInfo(shortcut.get(0), context);
infoUpdated = true;
}
- } else if (isNewApkAvailable && removedComponents.contains(cn)) {
+ } else if (!cn.getClassName().equals(IconCache.EMPTY_CLASS_NAME)) {
+ isTargetValid = context.getSystemService(LauncherApps.class)
+ .isActivityEnabled(cn, mUser);
+ }
+ if (si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) {
if (updateWorkspaceItemIntent(context, si, packageName)) {
infoUpdated = true;
+ } else if (si.hasPromiseIconUi()) {
+ removedShortcuts.add(si.id);
+ return;
}
- }
-
- if (isNewApkAvailable &&
- si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
- iconCache.getTitleAndIcon(si, si.usingLowResIcon());
+ } else if (!isTargetValid) {
+ removedShortcuts.add(si.id);
+ FileLog.e(TAG, "Restored shortcut no longer valid "
+ + si.getIntent());
+ return;
+ } else {
+ si.status = WorkspaceItemInfo.DEFAULT;
infoUpdated = true;
}
-
- int oldRuntimeFlags = si.runtimeStatusFlags;
- si.runtimeStatusFlags = flagOp.apply(si.runtimeStatusFlags);
- if (si.runtimeStatusFlags != oldRuntimeFlags) {
- shortcutUpdated = true;
+ } else if (isNewApkAvailable && removedComponents.contains(cn)) {
+ if (updateWorkspaceItemIntent(context, si, packageName)) {
+ infoUpdated = true;
}
}
- if (infoUpdated || shortcutUpdated) {
- updatedWorkspaceItems.add(si);
+ if (isNewApkAvailable
+ && si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
+ iconCache.getTitleAndIcon(si, si.usingLowResIcon());
+ infoUpdated = true;
}
- if (infoUpdated) {
- getModelWriter().updateItemInDatabase(si);
- }
- } else if (info instanceof LauncherAppWidgetInfo && isNewApkAvailable) {
- LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;
- if (mUser.equals(widgetInfo.user)
- && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
- && packageSet.contains(widgetInfo.providerName.getPackageName())) {
- widgetInfo.restoreStatus &=
- ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY &
- ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
- // adding this flag ensures that launcher shows 'click to setup'
- // if the widget has a config activity. In case there is no config
- // activity, it will be marked as 'restored' during bind.
- widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
-
- widgets.add(widgetInfo);
- getModelWriter().updateItemInDatabase(widgetInfo);
+ int oldRuntimeFlags = si.runtimeStatusFlags;
+ si.runtimeStatusFlags = flagOp.apply(si.runtimeStatusFlags);
+ if (si.runtimeStatusFlags != oldRuntimeFlags) {
+ shortcutUpdated = true;
}
}
+
+ if (infoUpdated || shortcutUpdated) {
+ updatedWorkspaceItems.add(si);
+ }
+ if (infoUpdated && si.id != ItemInfo.NO_ID) {
+ getModelWriter().updateItemInDatabase(si);
+ }
+ });
+
+ for (LauncherAppWidgetInfo widgetInfo : dataModel.appWidgets) {
+ if (mUser.equals(widgetInfo.user)
+ && widgetInfo.hasRestoreFlag(
+ LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
+ && packageSet.contains(widgetInfo.providerName.getPackageName())) {
+ widgetInfo.restoreStatus &=
+ ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY
+ & ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
+
+ // adding this flag ensures that launcher shows 'click to setup'
+ // if the widget has a config activity. In case there is no config
+ // activity, it will be marked as 'restored' during bind.
+ widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
+
+ widgets.add(widgetInfo);
+ getModelWriter().updateItemInDatabase(widgetInfo);
+ }
}
}
bindUpdatedWorkspaceItems(updatedWorkspaceItems);
if (!removedShortcuts.isEmpty()) {
- deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedShortcuts, false));
+ deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedShortcuts));
}
if (!widgets.isEmpty()) {
@@ -319,7 +324,7 @@
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
.or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
- .and(ItemInfoMatcher.ofItemIds(removedShortcuts, true));
+ .and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
deleteAndBindComponentsRemoved(removeMatch);
// Remove any queued items from the install queue
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 1cbe5c2..88006ba 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -21,7 +21,6 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
@@ -58,14 +57,14 @@
MultiHashMap<ShortcutKey, WorkspaceItemInfo> keyToShortcutInfo = new MultiHashMap<>();
HashSet<String> allIds = new HashSet<>();
- for (ItemInfo itemInfo : dataModel.itemsIdMap) {
- if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- WorkspaceItemInfo si = (WorkspaceItemInfo) itemInfo;
- if (mPackageName.equals(si.getIntent().getPackage()) && si.user.equals(mUser)) {
+ synchronized (dataModel) {
+ dataModel.forAllWorkspaceItemInfos(mUser, si -> {
+ if ((si.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
+ && mPackageName.equals(si.getIntent().getPackage())) {
keyToShortcutInfo.addToList(ShortcutKey.fromItemInfo(si), si);
allIds.add(si.getDeepShortcutId());
}
- }
+ });
}
final ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 7ec884f..5048e13 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -23,7 +23,6 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
@@ -73,27 +72,27 @@
ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
HashSet<ShortcutKey> removedKeys = new HashSet<>();
- for (ItemInfo itemInfo : dataModel.itemsIdMap) {
- if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
- && mUser.equals(itemInfo.user)) {
- WorkspaceItemInfo si = (WorkspaceItemInfo) itemInfo;
- if (mIsUserUnlocked) {
- ShortcutKey key = ShortcutKey.fromItemInfo(si);
- ShortcutInfo shortcut = pinnedShortcuts.get(key);
- // We couldn't verify the shortcut during loader. If its no longer available
- // (probably due to clear data), delete the workspace item as well
- if (shortcut == null) {
- removedKeys.add(key);
- continue;
+ synchronized (dataModel) {
+ dataModel.forAllWorkspaceItemInfos(mUser, si -> {
+ if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ if (mIsUserUnlocked) {
+ ShortcutKey key = ShortcutKey.fromItemInfo(si);
+ ShortcutInfo shortcut = pinnedShortcuts.get(key);
+ // We couldn't verify the shortcut during loader. If its no longer available
+ // (probably due to clear data), delete the workspace item as well
+ if (shortcut == null) {
+ removedKeys.add(key);
+ return;
+ }
+ si.runtimeStatusFlags &= ~FLAG_DISABLED_LOCKED_USER;
+ si.updateFromDeepShortcutInfo(shortcut, context);
+ app.getIconCache().getShortcutIcon(si, shortcut);
+ } else {
+ si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
}
- si.runtimeStatusFlags &= ~FLAG_DISABLED_LOCKED_USER;
- si.updateFromDeepShortcutInfo(shortcut, context);
- app.getIconCache().getShortcutIcon(si, shortcut);
- } else {
- si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
+ updatedWorkspaceItemInfos.add(si);
}
- updatedWorkspaceItemInfos.add(si);
- }
+ });
}
bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
if (!removedKeys.isEmpty()) {
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 38b3712..d4a132e 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -33,6 +33,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.widget.WidgetsFullSheet;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
@@ -92,6 +93,11 @@
l -> l.getAppsView().getActiveRecyclerView().getCurrentScrollY());
}
+ case TestProtocol.REQUEST_WIDGETS_SCROLL_Y: {
+ return getLauncherUIProperty(Bundle::putInt,
+ l -> WidgetsFullSheet.getWidgetsView(l).getCurrentScrollY());
+ }
+
case TestProtocol.REQUEST_WINDOW_INSETS: {
return getUIProperty(Bundle::putParcelable, a -> {
WindowInsets insets = a.getWindow()
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 3ca08fd..2644db8 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -81,6 +81,7 @@
public static final String REQUEST_UNFREEZE_APP_LIST = "unfreeze-app-list";
public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
public static final String REQUEST_APPS_LIST_SCROLL_Y = "apps-list-scroll-y";
+ public static final String REQUEST_WIDGETS_SCROLL_Y = "widgets-scroll-y";
public static final String REQUEST_WINDOW_INSETS = "window-insets";
public static final String REQUEST_PID = "pid";
public static final String REQUEST_TOTAL_PSS_KB = "total_pss";
@@ -106,4 +107,5 @@
public static final String PAUSE_NOT_DETECTED = "b/139891609";
public static final String OVERIEW_NOT_ALLAPPS = "b/156095088";
public static final String NO_SWIPE_TO_HOME = "b/158017601";
+ public static final String NO_SCROLL_END_WIDGETS = "b/160238801";
}
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 48c7734..c2bfb16 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -17,6 +17,7 @@
package com.android.launcher3.touch;
import static android.widget.ListPopupWindow.WRAP_CONTENT;
+
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
@@ -33,6 +34,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.widget.LinearLayout;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.PagedView;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.OverScroller;
@@ -260,4 +262,10 @@
}
return new ChildBounds(childHeight, childWidth, childBottom, childLeft);
}
+
+ @SuppressWarnings("SuspiciousNameCombination")
+ @Override
+ public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
+ return rect.left;
+ }
}
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 65b1a7a..b650526 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -96,6 +96,7 @@
int getTaskMenuWidth(View view);
int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout);
void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp);
+ int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect);
/**
* Maps the velocity from the coordinate plane of the foreground app to that
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 79e5c87..e87c887 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -32,6 +32,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.widget.LinearLayout;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.PagedView;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.OverScroller;
@@ -257,4 +258,9 @@
}
return new ChildBounds(childWidth, childHeight, childRight, childTop);
}
+
+ @Override
+ public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
+ return dp.heightPx - rect.bottom;
+ }
}
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index d5ae2dc..e91f16d 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -18,9 +18,11 @@
import android.content.res.Resources;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.view.Surface;
import android.view.View;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
@@ -77,4 +79,9 @@
view.setTranslationX(0);
view.setTranslationY(translation);
}
+
+ @Override
+ public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
+ return dp.widthPx - rect.right;
+ }
}
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index 4d5405d..e98af35 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -81,11 +81,10 @@
}
/**
- * Returns a new matcher which returns the opposite boolean value of the provided
- * {@param matcher}.
+ * Returns a new matcher with returns the opposite value of this.
*/
- static ItemInfoMatcher not(ItemInfoMatcher matcher) {
- return (info, cn) -> !matcher.matches(info, cn);
+ default ItemInfoMatcher negate() {
+ return (info, cn) -> !matches(info, cn);
}
static ItemInfoMatcher ofUser(UserHandle user) {
@@ -105,7 +104,10 @@
keys.contains(ShortcutKey.fromItemInfo(info));
}
- static ItemInfoMatcher ofItemIds(IntSparseArrayMap<Boolean> ids, Boolean matchDefault) {
- return (info, cn) -> ids.get(info.id, matchDefault);
+ /**
+ * Returns a matcher for items with provided ids
+ */
+ static ItemInfoMatcher ofItemIds(IntSet ids) {
+ return (info, cn) -> ids.contains(info.id);
}
}
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index d4e074c..26313e5 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -64,7 +64,7 @@
private static final Map<String, Integer> MAX_COUNTS;
static {
- Map<String, Integer> maxCounts = new ArrayMap<>(3);
+ Map<String, Integer> maxCounts = new ArrayMap<>(4);
maxCounts.put(HOME_BOUNCE_COUNT, 3);
maxCounts.put(SHELF_BOUNCE_COUNT, 3);
maxCounts.put(ALL_APPS_COUNT, 5);
diff --git a/src/com/android/launcher3/util/SecureSettingsObserver.java b/src/com/android/launcher3/util/SecureSettingsObserver.java
index 48aa02b..4b22429 100644
--- a/src/com/android/launcher3/util/SecureSettingsObserver.java
+++ b/src/com/android/launcher3/util/SecureSettingsObserver.java
@@ -29,6 +29,11 @@
/** Hidden field Settings.Secure.NOTIFICATION_BADGING */
public static final String NOTIFICATION_BADGING = "notification_badging";
+ /** Hidden field Settings.Secure.ONE_HANDED_MODE_ENABLED */
+ public static final String ONE_HANDED_ENABLED = "one_handed_mode_enabled";
+ /** Hidden field Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED */
+ public static final String ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED =
+ "swipe_bottom_to_notification_enabled";
private final ContentResolver mResolver;
private final String mKeySetting;
@@ -79,4 +84,21 @@
return new SecureSettingsObserver(
context.getContentResolver(), listener, NOTIFICATION_BADGING, 1);
}
+
+ public static SecureSettingsObserver newOneHandedSettingsObserver(Context context,
+ OnChangeListener listener) {
+ return new SecureSettingsObserver(
+ context.getContentResolver(), listener, ONE_HANDED_ENABLED, 1);
+ }
+
+ /**
+ * Constructs settings observer for {@link #ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED}
+ * preference.
+ */
+ public static SecureSettingsObserver newSwipeToNotificationSettingsObserver(Context context,
+ OnChangeListener listener) {
+ return new SecureSettingsObserver(
+ context.getContentResolver(), listener,
+ ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1);
+ }
}
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index b010b4b..2c75c74 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -292,6 +292,9 @@
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "BaseDragLayer: " + ev);
+ }
switch (ev.getAction()) {
case ACTION_DOWN: {
if ((mTouchDispatchState & TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS) != 0) {
diff --git a/src/com/android/launcher3/widget/WidgetsDiffReporter.java b/src/com/android/launcher3/widget/WidgetsDiffReporter.java
index df6e2c3..c9e80dc 100644
--- a/src/com/android/launcher3/widget/WidgetsDiffReporter.java
+++ b/src/com/android/launcher3/widget/WidgetsDiffReporter.java
@@ -20,8 +20,10 @@
import androidx.recyclerview.widget.RecyclerView;
+import com.android.launcher3.Utilities;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.widget.WidgetsListAdapter.WidgetListRowEntryComparator;
import java.util.ArrayList;
@@ -32,8 +34,8 @@
* methods accordingly.
*/
public class WidgetsDiffReporter {
- private static final boolean DEBUG = false;
- private static final String TAG = "WidgetsDiffReporter";
+ private static final boolean DEBUG = Utilities.IS_RUNNING_IN_TEST_HARNESS; // b/160238801
+ private static final String TAG = TestProtocol.NO_SCROLL_END_WIDGETS;
private final IconCache mIconCache;
private final RecyclerView.Adapter mListener;
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index 68a3ec5..ba55f5a 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -38,8 +39,10 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.TopRoundedCornerView;
@@ -68,6 +71,14 @@
}
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "WidgetsFullSheet: " + ev);
+ }
+ return super.dispatchTouchEvent(ev);
+ }
+
public WidgetsFullSheet(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index 82d4110..8f81977 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -120,6 +120,9 @@
public int getCurrentScrollY() {
// Skip early if widgets are not bound.
if (isModelNotReady() || getChildCount() == 0) {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "getCurrentScrollY: -1");
+ }
return -1;
}
@@ -128,6 +131,10 @@
int y = (child.getMeasuredHeight() * rowIndex);
int offset = getLayoutManager().getDecoratedTop(child);
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS,
+ "getCurrentScrollY: " + (getPaddingTop() + y - offset));
+ }
return getPaddingTop() + y - offset;
}
@@ -158,13 +165,23 @@
mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset);
}
if (mTouchDownOnScroller) {
- return mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
+ final boolean result = mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onInterceptTouchEvent 1 " + result);
+ }
+ return result;
+ }
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onInterceptTouchEvent 2 false");
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "WidgetsRecyclerView.onTouchEvent");
+ }
if (mTouchDownOnScroller) {
mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
}
@@ -172,5 +189,31 @@
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onRequestDisallowInterceptTouchEvent "
+ + disallowIntercept);
+ }
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ final boolean result = super.dispatchTouchEvent(ev);
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "WidgetsRecyclerView: state: "
+ + getScrollState()
+ + " can scroll: " + getLayoutManager().canScrollVertically()
+ + " result: " + result
+ + " layout suppressed: " + isLayoutSuppressed()
+ + " event: " + ev);
+ }
+ return result;
+ }
+
+ @Override
+ public void stopNestedScroll() {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "stopNestedScroll");
+ }
+ super.stopNestedScroll();
}
}
\ No newline at end of file
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 1c8f095..f243f27 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -29,6 +29,7 @@
<receiver
android:name="com.android.launcher3.testcomponent.AppWidgetNoConfig"
+ android:exported="true"
android:label="No Config">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
@@ -39,6 +40,7 @@
<receiver
android:name="com.android.launcher3.testcomponent.AppWdigetHidden"
+ android:exported="true"
android:label="Hidden widget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
@@ -49,6 +51,7 @@
<receiver
android:name="com.android.launcher3.testcomponent.AppWidgetWithConfig"
+ android:exported="true"
android:label="With Config">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
@@ -58,12 +61,14 @@
</receiver>
<activity
- android:name="com.android.launcher3.testcomponent.WidgetConfigActivity">
+ android:name="com.android.launcher3.testcomponent.WidgetConfigActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
- <activity android:name="com.android.launcher3.testcomponent.CustomShortcutConfigActivity">
+ <activity android:name="com.android.launcher3.testcomponent.CustomShortcutConfigActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" />
<category android:name="android.intent.category.DEFAULT" />
@@ -72,6 +77,7 @@
<activity
android:name="com.android.launcher3.testcomponent.RequestPinItemActivity"
android:icon="@drawable/test_drawable_pin_item"
+ android:exported="true"
android:label="Test Pin Item">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -102,6 +108,7 @@
android:stateNotNeeded="true"
android:taskAffinity=""
android:theme="@android:style/Theme.DeviceDefault.Light"
+ android:exported="true"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -114,6 +121,7 @@
<activity
android:name="com.android.launcher3.testcomponent.BaseTestingActivity"
android:label="LauncherTestApp"
+ android:exported="true"
android:taskAffinity="com.android.launcher3.testcomponent.Affinity1">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -128,6 +136,7 @@
</activity>
<activity-alias android:name="Activity2"
android:label="TestActivity2"
+ android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -136,6 +145,7 @@
</activity-alias>
<activity-alias android:name="Activity3"
android:label="TestActivity3"
+ android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -144,6 +154,7 @@
</activity-alias>
<activity-alias android:name="Activity4"
android:label="TestActivity4"
+ android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -152,6 +163,7 @@
</activity-alias>
<activity-alias android:name="Activity5"
android:label="TestActivity5"
+ android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -160,6 +172,7 @@
</activity-alias>
<activity-alias android:name="Activity6"
android:label="TestActivity6"
+ android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -168,6 +181,7 @@
</activity-alias>
<activity-alias android:name="Activity7"
android:label="TestActivity7"
+ android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -176,6 +190,7 @@
</activity-alias>
<activity-alias android:name="Activity8"
android:label="TestActivity8"
+ android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -184,6 +199,7 @@
</activity-alias>
<activity-alias android:name="Activity9"
android:label="TestActivity9"
+ android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -192,6 +208,7 @@
</activity-alias>
<activity-alias android:name="Activity10"
android:label="TestActivity10"
+ android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -200,6 +217,7 @@
</activity-alias>
<activity-alias android:name="Activity11"
android:label="TestActivity11"
+ android:exported="true"
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/tests/dummy_app/AndroidManifest.xml b/tests/dummy_app/AndroidManifest.xml
index f00138c..d5e2320 100644
--- a/tests/dummy_app/AndroidManifest.xml
+++ b/tests/dummy_app/AndroidManifest.xml
@@ -26,6 +26,7 @@
<activity
android:name="Activity1"
android:icon="@mipmap/ic_launcher1"
+ android:exported="true"
android:label="Aardwolf">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/tests/src/com/android/launcher3/ui/ActivityLeakTracker.java b/tests/src/com/android/launcher3/ui/ActivityLeakTracker.java
index 202dcb1..dd216c7 100644
--- a/tests/src/com/android/launcher3/ui/ActivityLeakTracker.java
+++ b/tests/src/com/android/launcher3/ui/ActivityLeakTracker.java
@@ -73,20 +73,12 @@
}
public boolean noLeakedActivities() {
- int liveActivities = 0;
- int destroyedActivities = 0;
-
for (Activity activity : mActivities.keySet()) {
if (activity.isDestroyed()) {
- ++destroyedActivities;
- } else {
- ++liveActivities;
+ return false;
}
}
- if (liveActivities > 2) return false;
-
- // It's OK to have 1 leaked activity if no active activities exist.
- return liveActivities == 0 ? destroyedActivities <= 1 : destroyedActivities == 0;
+ return mActivities.size() <= 2;
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index f4274a8..bf079cb 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -635,9 +635,11 @@
Parcelable executeAndWaitForEvent(Runnable command,
UiAutomation.AccessibilityEventFilter eventFilter, Supplier<String> message) {
try {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "executeAndWaitForEvent: before");
final AccessibilityEvent event =
mInstrumentation.getUiAutomation().executeAndWaitForEvent(
command, eventFilter, WAIT_TIME_MS);
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "executeAndWaitForEvent: after");
assertNotNull("executeAndWaitForEvent returned null (this can't happen)", event);
final Parcelable parcelableData = event.getParcelableData();
event.recycle();
@@ -1094,7 +1096,10 @@
executeAndWaitForEvent(
() -> linearGesture(
startX, startY, endX, endY, steps, slowDown, GestureScope.INSIDE),
- event -> TestProtocol.SCROLL_FINISHED_MESSAGE.equals(event.getClassName()),
+ event -> {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "scroll: received event: " + event);
+ return TestProtocol.SCROLL_FINISHED_MESSAGE.equals(event.getClassName());
+ },
() -> "Didn't receive a scroll end message: " + startX + ", " + startY
+ ", " + endX + ", " + endY);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
index 4440b82..ab6465c 100644
--- a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
+++ b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
@@ -57,6 +57,8 @@
while (true) {
rawEvents = mLauncher.getTestInfo(TestProtocol.REQUEST_GET_TEST_EVENTS)
.getStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ if (rawEvents == null) return null;
+
final int expectedCount = mExpectedEvents.entrySet()
.stream().mapToInt(e -> e.getValue().size()).sum();
if (rawEvents.size() >= expectedCount
@@ -83,6 +85,7 @@
String verify(long waitForExpectedCountMs, boolean successfulGesture) {
final ListMap<String> actualEvents = finishSync(waitForExpectedCountMs);
+ if (actualEvents == null) return "null event sequences because launcher likely died";
final StringBuilder sb = new StringBuilder();
boolean hasMismatches = false;
@@ -91,8 +94,7 @@
List<String> actual = new ArrayList<>(actualEvents.getNonNull(sequence));
final int mismatchPosition = getMismatchPosition(expectedEvents.getValue(), actual);
- hasMismatches = hasMismatches
- || mismatchPosition != -1 && !ignoreMistatch(successfulGesture, sequence);
+ hasMismatches = hasMismatches || mismatchPosition != -1;
formatSequenceWithMismatch(
sb,
sequence,
@@ -103,8 +105,7 @@
// Check for unexpected event sequences in the actual data.
for (String actualNamedSequence : actualEvents.keySet()) {
if (!mExpectedEvents.containsKey(actualNamedSequence)) {
- hasMismatches = hasMismatches
- || !ignoreMistatch(successfulGesture, actualNamedSequence);
+ hasMismatches = true;
formatSequenceWithMismatch(
sb,
actualNamedSequence,
@@ -117,13 +118,6 @@
return hasMismatches ? "mismatching events: " + sb.toString() : null;
}
- // Workaround for b/154157191
- private static boolean ignoreMistatch(boolean successfulGesture, String sequence) {
- // b/156287114
- return false;
-// return TestProtocol.SEQUENCE_TIS.equals(sequence) && successfulGesture;
- }
-
// If the list of actual events matches the list of expected events, returns -1, otherwise
// the position of the mismatch.
private static int getMismatchPosition(List<Pattern> expected, List<String> actual) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 39ac645..49af616 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -28,6 +28,7 @@
import androidx.test.uiautomator.Until;
import com.android.launcher3.tapl.LauncherInstrumentation.GestureScope;
+import com.android.launcher3.testing.TestProtocol;
import java.util.Collection;
@@ -90,6 +91,12 @@
return LauncherInstrumentation.ContainerType.WIDGETS;
}
+ private int getWidgetsScroll() {
+ return mLauncher.getTestInfo(
+ TestProtocol.REQUEST_WIDGETS_SCROLL_Y)
+ .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
public Widget getWidget(String labelText) {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
@@ -136,7 +143,13 @@
}
mLauncher.assertTrue("Too many attempts", ++i <= 40);
+ final int scroll = getWidgetsScroll();
mLauncher.scrollToLastVisibleRow(widgetsContainer, cells, 0);
+ final int newScroll = getWidgetsScroll();
+ mLauncher.assertTrue(
+ "Scrolled in a wrong direction in Widgets: from " + scroll + " to "
+ + newScroll, newScroll >= scroll);
+ mLauncher.assertTrue("Unable to scroll to the widget", newScroll != scroll);
}
}
}