Merging from ub-launcher3-rvc-qpr-dev @ build 6690853
Bug:150504032 Test: manual, presubmit on the source branch x20/teams/android-launcher/merge/ub-launcher3-rvc-qpr-dev-rvc-qpr-dev_6690853.html Change-Id: Ie86b0a2e0d82646a0c3d44a0214cbb985435320d Merged-In: Ibff46b3ef7ff89accb459db323f31179adb4ef21
This commit is contained in:
commit
65b16d6db2
|
@ -45,9 +45,6 @@
|
||||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
||||||
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
|
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
|
||||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
<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
|
Permissions required for read/write access to the workspace data. These permission name
|
||||||
|
@ -86,6 +83,7 @@
|
||||||
<receiver
|
<receiver
|
||||||
android:name="com.android.launcher3.InstallShortcutReceiver"
|
android:name="com.android.launcher3.InstallShortcutReceiver"
|
||||||
android:permission="com.android.launcher.permission.INSTALL_SHORTCUT"
|
android:permission="com.android.launcher.permission.INSTALL_SHORTCUT"
|
||||||
|
android:exported="true"
|
||||||
android:enabled="@bool/enable_install_shortcut_api" >
|
android:enabled="@bool/enable_install_shortcut_api" >
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.android.launcher.action.INSTALL_SHORTCUT" />
|
<action android:name="com.android.launcher.action.INSTALL_SHORTCUT" />
|
||||||
|
@ -94,14 +92,16 @@
|
||||||
|
|
||||||
<!-- Intent received when a session is committed -->
|
<!-- Intent received when a session is committed -->
|
||||||
<receiver
|
<receiver
|
||||||
android:name="com.android.launcher3.SessionCommitReceiver" >
|
android:name="com.android.launcher3.SessionCommitReceiver"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.content.pm.action.SESSION_COMMITTED" />
|
<action android:name="android.content.pm.action.SESSION_COMMITTED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<!-- Intent received used to initialize a restored widget -->
|
<!-- 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>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_HOST_RESTORED"/>
|
<action android:name="android.appwidget.action.APPWIDGET_HOST_RESTORED"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
@ -117,6 +117,7 @@
|
||||||
android:name="com.android.launcher3.notification.NotificationListener"
|
android:name="com.android.launcher3.notification.NotificationListener"
|
||||||
android:label="@string/notification_dots_service_title"
|
android:label="@string/notification_dots_service_title"
|
||||||
android:enabled="@bool/notification_dots_enabled"
|
android:enabled="@bool/notification_dots_enabled"
|
||||||
|
android:exported="true"
|
||||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.service.notification.NotificationListenerService" />
|
<action android:name="android.service.notification.NotificationListenerService" />
|
||||||
|
@ -130,6 +131,7 @@
|
||||||
android:theme="@style/AppItemActivityTheme"
|
android:theme="@style/AppItemActivityTheme"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:autoRemoveFromRecents="true"
|
android:autoRemoveFromRecents="true"
|
||||||
|
android:exported="true"
|
||||||
android:label="@string/action_add_to_workspace" >
|
android:label="@string/action_add_to_workspace" >
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
|
<action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
|
||||||
|
@ -165,6 +167,7 @@
|
||||||
android:name="com.android.launcher3.settings.SettingsActivity"
|
android:name="com.android.launcher3.settings.SettingsActivity"
|
||||||
android:label="@string/settings_button_text"
|
android:label="@string/settings_button_text"
|
||||||
android:theme="@style/HomeSettingsTheme"
|
android:theme="@style/HomeSettingsTheme"
|
||||||
|
android:exported="true"
|
||||||
android:autoRemoveFromRecents="true">
|
android:autoRemoveFromRecents="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||||
|
@ -187,6 +190,7 @@
|
||||||
android:name="com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher"
|
android:name="com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
|
android:exported="true"
|
||||||
android:enabled="true">
|
android:enabled="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
android:resizeableActivity="true"
|
android:resizeableActivity="true"
|
||||||
android:resumeWhilePausing="true"
|
android:resumeWhilePausing="true"
|
||||||
android:taskAffinity=""
|
android:taskAffinity=""
|
||||||
|
android:exported="true"
|
||||||
android:enabled="true">
|
android:enabled="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
|
@ -164,6 +164,12 @@ public class DebugTestInformationHandler extends TestInformationHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
case TestProtocol.REQUEST_GET_TEST_EVENTS: {
|
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) {
|
synchronized (sEvents) {
|
||||||
response.putStringArrayList(
|
response.putStringArrayList(
|
||||||
TestProtocol.TEST_INFO_RESPONSE_FIELD, new ArrayList<>(sEvents));
|
TestProtocol.TEST_INFO_RESPONSE_FIELD, new ArrayList<>(sEvents));
|
||||||
|
|
|
@ -131,6 +131,7 @@ message Application {
|
||||||
// Legacy shortcuts and shortcuts handled by ShortcutManager
|
// Legacy shortcuts and shortcuts handled by ShortcutManager
|
||||||
message Shortcut {
|
message Shortcut {
|
||||||
optional string shortcut_name = 1;
|
optional string shortcut_name = 1;
|
||||||
|
optional string shortcut_id = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppWidgets handled by AppWidgetManager
|
// AppWidgets handled by AppWidgetManager
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
android:resizeableActivity="true"
|
android:resizeableActivity="true"
|
||||||
android:resumeWhilePausing="true"
|
android:resumeWhilePausing="true"
|
||||||
android:taskAffinity=""
|
android:taskAffinity=""
|
||||||
|
android:exported="true"
|
||||||
android:enabled="true">
|
android:enabled="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
|
@ -17,97 +17,91 @@
|
||||||
** limitations under the License.
|
** 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:name="${packageName}.permission.HOTSEAT_EDU"
|
||||||
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
|
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
|
||||||
android:protectionLevel="signatureOrSystem" />
|
android:protectionLevel="signatureOrSystem" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
|
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
|
||||||
<uses-permission android:name="${packageName}.permission.HOTSEAT_EDU" />
|
<uses-permission android:name="${packageName}.permission.HOTSEAT_EDU" />
|
||||||
|
|
||||||
<application
|
<application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
|
||||||
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
|
android:fullBackupOnly="true"
|
||||||
android:fullBackupOnly="true"
|
android:fullBackupContent="@xml/backupscheme"
|
||||||
android:fullBackupContent="@xml/backupscheme"
|
android:hardwareAccelerated="true"
|
||||||
android:hardwareAccelerated="true"
|
android:icon="@drawable/ic_launcher_home"
|
||||||
android:icon="@drawable/ic_launcher_home"
|
android:label="@string/derived_app_name"
|
||||||
android:label="@string/derived_app_name"
|
android:theme="@style/AppTheme"
|
||||||
android:theme="@style/AppTheme"
|
android:largeHeap="@bool/config_largeHeap"
|
||||||
android:largeHeap="@bool/config_largeHeap"
|
android:restoreAnyVersion="true"
|
||||||
android:restoreAnyVersion="true"
|
android:supportsRtl="true">
|
||||||
android:supportsRtl="true" >
|
|
||||||
|
|
||||||
<service
|
<service android:name="com.android.quickstep.TouchInteractionService"
|
||||||
android:name="com.android.quickstep.TouchInteractionService"
|
android:permission="android.permission.STATUS_BAR_SERVICE"
|
||||||
android:permission="android.permission.STATUS_BAR_SERVICE"
|
android:directBootAware="true"
|
||||||
android:directBootAware="true" >
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.QUICKSTEP_SERVICE" />
|
<action android:name="android.intent.action.QUICKSTEP_SERVICE"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<activity android:name="com.android.quickstep.RecentsActivity"
|
<activity android:name="com.android.quickstep.RecentsActivity"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:clearTaskOnLaunch="true"
|
android:clearTaskOnLaunch="true"
|
||||||
android:stateNotNeeded="true"
|
android:stateNotNeeded="true"
|
||||||
android:theme="@style/LauncherTheme"
|
android:theme="@style/LauncherTheme"
|
||||||
android:screenOrientation="unspecified"
|
android:screenOrientation="unspecified"
|
||||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
|
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
|
||||||
android:resizeableActivity="true"
|
android:resizeableActivity="true"
|
||||||
android:resumeWhilePausing="true"
|
android:resumeWhilePausing="true"
|
||||||
android:taskAffinity="" />
|
android:taskAffinity=""/>
|
||||||
|
|
||||||
<!-- Content provider to settings search. The autority should be same as the packageName -->
|
<!-- Content provider to settings search. The autority should be same as the packageName -->
|
||||||
<provider
|
<provider android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
|
||||||
android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
|
android:authorities="${packageName}"
|
||||||
android:authorities="${packageName}"
|
android:grantUriPermissions="true"
|
||||||
android:grantUriPermissions="true"
|
android:multiprocess="true"
|
||||||
android:multiprocess="true"
|
android:permission="android.permission.READ_SEARCH_INDEXABLES"
|
||||||
android:permission="android.permission.READ_SEARCH_INDEXABLES"
|
android:exported="true">
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" />
|
<action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
<!-- FileProvider used for sharing images. -->
|
<!-- FileProvider used for sharing images. -->
|
||||||
<provider
|
<provider android:name="androidx.core.content.FileProvider"
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:authorities="${packageName}.overview.fileprovider"
|
||||||
android:authorities="${packageName}.overview.fileprovider"
|
android:exported="false"
|
||||||
android:exported="false"
|
android:grantUriPermissions="true">
|
||||||
android:grantUriPermissions="true">
|
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
<meta-data
|
android:resource="@xml/overview_file_provider_paths"/>
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
|
||||||
android:resource="@xml/overview_file_provider_paths" />
|
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
<service
|
<service android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
|
||||||
android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
|
tools:node="remove"/>
|
||||||
tools:node="remove" />
|
|
||||||
|
|
||||||
<activity
|
<activity android:name="com.android.launcher3.proxy.ProxyActivityStarter"
|
||||||
android:name="com.android.launcher3.proxy.ProxyActivityStarter"
|
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
|
||||||
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
|
android:launchMode="singleTask"
|
||||||
android:launchMode="singleTask"
|
android:clearTaskOnLaunch="true"
|
||||||
android:clearTaskOnLaunch="true"
|
android:exported="false"/>
|
||||||
android:exported="false" />
|
|
||||||
|
|
||||||
<activity
|
<activity android:name="com.android.quickstep.interaction.GestureSandboxActivity"
|
||||||
android:name="com.android.quickstep.interaction.GestureSandboxActivity"
|
android:autoRemoveFromRecents="true"
|
||||||
android:autoRemoveFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:excludeFromRecents="true"
|
android:screenOrientation="portrait"
|
||||||
android:screenOrientation="portrait">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.android.quickstep.action.GESTURE_SANDBOX" />
|
<action android:name="com.android.quickstep.action.GESTURE_SANDBOX"/>
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
|
@ -116,7 +110,8 @@
|
||||||
android:noHistory="true"
|
android:noHistory="true"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:clearTaskOnLaunch="true"
|
android:clearTaskOnLaunch="true"
|
||||||
android:permission="${packageName}.permission.HOTSEAT_EDU">
|
android:permission="${packageName}.permission.HOTSEAT_EDU"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU"/>
|
<action android:name="com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU"/>
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
|
@ -16,6 +16,12 @@
|
||||||
package com.android.launcher3.appprediction;
|
package com.android.launcher3.appprediction;
|
||||||
|
|
||||||
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID;
|
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID;
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST;
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT;
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
|
||||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
|
@ -31,29 +37,38 @@ import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import android.os.Process;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.AnyThread;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
import com.android.launcher3.InvariantDeviceProfile;
|
import com.android.launcher3.InvariantDeviceProfile;
|
||||||
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
||||||
|
import com.android.launcher3.logger.LauncherAtom;
|
||||||
|
import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
|
||||||
|
import com.android.launcher3.logger.LauncherAtom.FolderContainer;
|
||||||
|
import com.android.launcher3.logger.LauncherAtom.HotseatContainer;
|
||||||
|
import com.android.launcher3.logger.LauncherAtom.WorkspaceContainer;
|
||||||
|
import com.android.launcher3.logging.StatsLogManager.EventEnum;
|
||||||
import com.android.launcher3.model.AppLaunchTracker;
|
import com.android.launcher3.model.AppLaunchTracker;
|
||||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
import com.android.launcher3.pm.UserCache;
|
||||||
import com.android.systemui.plugins.AppLaunchEventsPlugin;
|
import com.android.quickstep.logging.StatsLogCompatManager;
|
||||||
import com.android.systemui.plugins.PluginListener;
|
import com.android.quickstep.logging.StatsLogCompatManager.StatsLogConsumer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Locale;
|
||||||
import java.util.List;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclass of app tracker which publishes the data to the prediction engine and gets back results.
|
* Subclass of app tracker which publishes the data to the prediction engine and gets back results.
|
||||||
*/
|
*/
|
||||||
@TargetApi(Build.VERSION_CODES.Q)
|
@TargetApi(Build.VERSION_CODES.Q)
|
||||||
public class PredictionAppTracker extends AppLaunchTracker
|
public class PredictionAppTracker extends AppLaunchTracker implements StatsLogConsumer {
|
||||||
implements PluginListener<AppLaunchEventsPlugin> {
|
|
||||||
|
|
||||||
private static final String TAG = "PredictionAppTracker";
|
private static final String TAG = "PredictionAppTracker";
|
||||||
private static final boolean DBG = false;
|
private static final boolean DBG = false;
|
||||||
|
@ -65,11 +80,9 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||||
|
|
||||||
protected final Context mContext;
|
protected final Context mContext;
|
||||||
private final Handler mMessageHandler;
|
private final Handler mMessageHandler;
|
||||||
private final List<AppLaunchEventsPlugin> mAppLaunchEventsPluginsList;
|
|
||||||
|
|
||||||
// Accessed only on worker thread
|
// Accessed only on worker thread
|
||||||
private AppPredictor mHomeAppPredictor;
|
private AppPredictor mHomeAppPredictor;
|
||||||
private AppPredictor mRecentsOverviewPredictor;
|
|
||||||
|
|
||||||
public PredictionAppTracker(Context context) {
|
public PredictionAppTracker(Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
@ -77,10 +90,6 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||||
InvariantDeviceProfile.INSTANCE.get(mContext).addOnChangeListener(this::onIdpChanged);
|
InvariantDeviceProfile.INSTANCE.get(mContext).addOnChangeListener(this::onIdpChanged);
|
||||||
|
|
||||||
mMessageHandler.sendEmptyMessage(MSG_INIT);
|
mMessageHandler.sendEmptyMessage(MSG_INIT);
|
||||||
|
|
||||||
mAppLaunchEventsPluginsList = new ArrayList<>();
|
|
||||||
PluginManagerWrapper.INSTANCE.get(context)
|
|
||||||
.addPluginListener(this, AppLaunchEventsPlugin.class, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
|
@ -97,10 +106,7 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||||
mHomeAppPredictor.destroy();
|
mHomeAppPredictor.destroy();
|
||||||
mHomeAppPredictor = null;
|
mHomeAppPredictor = null;
|
||||||
}
|
}
|
||||||
if (mRecentsOverviewPredictor != null) {
|
StatsLogCompatManager.LOGS_CONSUMER.remove(this);
|
||||||
mRecentsOverviewPredictor.destroy();
|
|
||||||
mRecentsOverviewPredictor = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
|
@ -142,7 +148,7 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||||
// Initialize the clients
|
// Initialize the clients
|
||||||
int count = InvariantDeviceProfile.INSTANCE.get(mContext).numAllAppsColumns;
|
int count = InvariantDeviceProfile.INSTANCE.get(mContext).numAllAppsColumns;
|
||||||
mHomeAppPredictor = createPredictor(Client.HOME, count);
|
mHomeAppPredictor = createPredictor(Client.HOME, count);
|
||||||
mRecentsOverviewPredictor = createPredictor(Client.OVERVIEW, count);
|
StatsLogCompatManager.LOGS_CONSUMER.add(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case MSG_DESTROY: {
|
case MSG_DESTROY: {
|
||||||
|
@ -157,12 +163,7 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||||
}
|
}
|
||||||
case MSG_PREDICT: {
|
case MSG_PREDICT: {
|
||||||
if (mHomeAppPredictor != null) {
|
if (mHomeAppPredictor != null) {
|
||||||
String client = (String) msg.obj;
|
mHomeAppPredictor.requestPredictionUpdate();
|
||||||
if (Client.HOME.id.equals(client)) {
|
|
||||||
mHomeAppPredictor.requestPredictionUpdate();
|
|
||||||
} else {
|
|
||||||
mRecentsOverviewPredictor.requestPredictionUpdate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -179,98 +180,142 @@ public class PredictionAppTracker extends AppLaunchTracker
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
Log.d(TAG, String.format("Sent immediate message to update %s", client));
|
Log.d(TAG, String.format("Sent immediate message to update %s", client));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Relay onReturnedToHome to every plugin.
|
|
||||||
mAppLaunchEventsPluginsList.forEach(AppLaunchEventsPlugin::onReturnedToHome);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@AnyThread
|
||||||
@UiThread
|
private void sendEvent(LauncherAtom.ItemInfo atomInfo, int eventId) {
|
||||||
public void onStartShortcut(String packageName, String shortcutId, UserHandle user,
|
AppTarget target = toAppTarget(atomInfo);
|
||||||
String container) {
|
if (target != null) {
|
||||||
// TODO: Use the full shortcut info
|
AppTargetEvent event = new AppTargetEvent.Builder(target, eventId)
|
||||||
AppTarget target = new AppTarget.Builder(
|
.setLaunchLocation(getContainer(atomInfo))
|
||||||
new AppTargetId("shortcut:" + shortcutId), packageName, user)
|
|
||||||
.setClassName(shortcutId)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
sendLaunch(target, container);
|
|
||||||
|
|
||||||
// Relay onStartShortcut info to every connected plugin.
|
|
||||||
mAppLaunchEventsPluginsList
|
|
||||||
.forEach(plugin -> plugin.onStartShortcut(
|
|
||||||
packageName,
|
|
||||||
shortcutId,
|
|
||||||
user,
|
|
||||||
container != null ? container : CONTAINER_DEFAULT)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@UiThread
|
|
||||||
public void onStartApp(ComponentName cn, UserHandle user, String container) {
|
|
||||||
if (cn != null) {
|
|
||||||
AppTarget target = new AppTarget.Builder(
|
|
||||||
new AppTargetId("app:" + cn), cn.getPackageName(), user)
|
|
||||||
.setClassName(cn.getClassName())
|
|
||||||
.build();
|
.build();
|
||||||
sendLaunch(target, container);
|
Message.obtain(mMessageHandler, MSG_LAUNCH, event).sendToTarget();
|
||||||
|
|
||||||
// Relay onStartApp to every connected plugin.
|
|
||||||
mAppLaunchEventsPluginsList
|
|
||||||
.forEach(plugin -> plugin.onStartApp(
|
|
||||||
cn,
|
|
||||||
user,
|
|
||||||
container != null ? container : CONTAINER_DEFAULT)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@UiThread
|
public void consume(EventEnum event, LauncherAtom.ItemInfo atomInfo) {
|
||||||
public void onDismissApp(ComponentName cn, UserHandle user, String container) {
|
if (event == LAUNCHER_APP_LAUNCH_TAP
|
||||||
if (cn == null) return;
|
|| event == LAUNCHER_TASK_LAUNCH_SWIPE_DOWN
|
||||||
AppTarget target = new AppTarget.Builder(
|
|| event == LAUNCHER_TASK_LAUNCH_TAP
|
||||||
new AppTargetId("app: " + cn), cn.getPackageName(), user)
|
|| event == LAUNCHER_QUICKSWITCH_RIGHT
|
||||||
.setClassName(cn.getClassName())
|
|| event == LAUNCHER_QUICKSWITCH_LEFT) {
|
||||||
.build();
|
sendEvent(atomInfo, AppTargetEvent.ACTION_LAUNCH);
|
||||||
sendDismiss(target, container);
|
} else if (event == LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST) {
|
||||||
|
sendEvent(atomInfo, AppTargetEvent.ACTION_DISMISS);
|
||||||
// Relay onDismissApp to every connected plugin.
|
}
|
||||||
mAppLaunchEventsPluginsList
|
|
||||||
.forEach(plugin -> plugin.onDismissApp(
|
|
||||||
cn,
|
|
||||||
user,
|
|
||||||
container != null ? container : CONTAINER_DEFAULT)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@Nullable
|
||||||
private void sendEvent(AppTarget target, String container, int eventId) {
|
private AppTarget toAppTarget(LauncherAtom.ItemInfo info) {
|
||||||
AppTargetEvent event = new AppTargetEvent.Builder(target, eventId)
|
UserHandle userHandle = Process.myUserHandle();
|
||||||
.setLaunchLocation(container == null ? CONTAINER_DEFAULT : container)
|
if (info.getIsWork()) {
|
||||||
.build();
|
userHandle = UserCache.INSTANCE.get(mContext).getUserProfiles().stream()
|
||||||
Message.obtain(mMessageHandler, MSG_LAUNCH, event).sendToTarget();
|
.filter(((Predicate<UserHandle>) userHandle::equals).negate())
|
||||||
|
.findAny()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
if (userHandle == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ComponentName cn = null;
|
||||||
|
String id = null;
|
||||||
|
|
||||||
|
switch (info.getItemCase()) {
|
||||||
|
case APPLICATION: {
|
||||||
|
LauncherAtom.Application app = info.getApplication();
|
||||||
|
if ((cn = parseNullable(app.getComponentName())) != null) {
|
||||||
|
id = "app:" + cn.getPackageName();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SHORTCUT: {
|
||||||
|
LauncherAtom.Shortcut si = info.getShortcut();
|
||||||
|
if (!TextUtils.isEmpty(si.getShortcutId())
|
||||||
|
&& (cn = parseNullable(si.getShortcutName())) != null) {
|
||||||
|
id = "shortcut:" + si.getShortcutId();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WIDGET: {
|
||||||
|
LauncherAtom.Widget widget = info.getWidget();
|
||||||
|
if ((cn = parseNullable(widget.getComponentName())) != null) {
|
||||||
|
id = "widget:" + cn.getPackageName();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TASK: {
|
||||||
|
LauncherAtom.Task task = info.getTask();
|
||||||
|
if ((cn = parseNullable(task.getComponentName())) != null) {
|
||||||
|
id = "app:" + cn.getPackageName();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FOLDER_ICON: {
|
||||||
|
id = "folder:" + SystemClock.uptimeMillis();
|
||||||
|
cn = new ComponentName(mContext.getPackageName(), "#folder");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (id != null && cn != null) {
|
||||||
|
return new AppTarget.Builder(new AppTargetId(id), cn.getPackageName(), userHandle)
|
||||||
|
.setClassName(cn.getClassName())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
private String getContainer(LauncherAtom.ItemInfo info) {
|
||||||
private void sendLaunch(AppTarget target, String container) {
|
ContainerInfo ci = info.getContainerInfo();
|
||||||
sendEvent(target, container, AppTargetEvent.ACTION_LAUNCH);
|
switch (ci.getContainerCase()) {
|
||||||
|
case WORKSPACE: {
|
||||||
|
// In case the item type is not widgets, the spaceX and spanY default to 1.
|
||||||
|
int spanX = info.getWidget().getSpanX();
|
||||||
|
int spanY = info.getWidget().getSpanY();
|
||||||
|
return getWorkspaceContainerString(ci.getWorkspace(), spanX, spanY);
|
||||||
|
}
|
||||||
|
case HOTSEAT: {
|
||||||
|
return getHotseatContainerString(ci.getHotseat());
|
||||||
|
}
|
||||||
|
case TASK_SWITCHER_CONTAINER: {
|
||||||
|
return "task-switcher";
|
||||||
|
}
|
||||||
|
case ALL_APPS_CONTAINER: {
|
||||||
|
return "all-apps";
|
||||||
|
}
|
||||||
|
case SEARCH_RESULT_CONTAINER: {
|
||||||
|
return "search-results";
|
||||||
|
}
|
||||||
|
case PREDICTED_HOTSEAT_CONTAINER: {
|
||||||
|
return "predictions/hotseat";
|
||||||
|
}
|
||||||
|
case PREDICTION_CONTAINER: {
|
||||||
|
return "predictions";
|
||||||
|
}
|
||||||
|
case FOLDER: {
|
||||||
|
FolderContainer fc = ci.getFolder();
|
||||||
|
switch (fc.getParentContainerCase()) {
|
||||||
|
case WORKSPACE:
|
||||||
|
return "folder/" + getWorkspaceContainerString(fc.getWorkspace(), 1, 1);
|
||||||
|
case HOTSEAT:
|
||||||
|
return "folder/" + getHotseatContainerString(fc.getHotseat());
|
||||||
|
}
|
||||||
|
return "folder";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
private static String getWorkspaceContainerString(WorkspaceContainer wc, int spanX, int spanY) {
|
||||||
private void sendDismiss(AppTarget target, String container) {
|
return String.format(Locale.ENGLISH, "workspace/%d/[%d,%d]/[%d,%d]",
|
||||||
sendEvent(target, container, AppTargetEvent.ACTION_DISMISS);
|
wc.getPageIndex(), wc.getGridX(), wc.getGridY(), spanX, spanY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static String getHotseatContainerString(HotseatContainer hc) {
|
||||||
public void onPluginConnected(AppLaunchEventsPlugin appLaunchEventsPlugin, Context context) {
|
return String.format(Locale.ENGLISH, "hotseat/%d", hc.getIndex());
|
||||||
mAppLaunchEventsPluginsList.add(appLaunchEventsPlugin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static ComponentName parseNullable(String componentNameString) {
|
||||||
public void onPluginDisconnected(AppLaunchEventsPlugin appLaunchEventsPlugin) {
|
return TextUtils.isEmpty(componentNameString)
|
||||||
mAppLaunchEventsPluginsList.remove(appLaunchEventsPlugin);
|
? null : ComponentName.unflattenFromString(componentNameString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,6 @@ import com.android.launcher3.config.FeatureFlags;
|
||||||
import com.android.launcher3.keyboard.FocusIndicatorHelper;
|
import com.android.launcher3.keyboard.FocusIndicatorHelper;
|
||||||
import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
|
import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
|
||||||
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
|
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
|
||||||
import com.android.launcher3.model.AppLaunchTracker;
|
|
||||||
import com.android.launcher3.model.data.AppInfo;
|
import com.android.launcher3.model.data.AppInfo;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||||
|
@ -93,9 +92,6 @@ public class PredictionRowView extends LinearLayout implements
|
||||||
private static final Interpolator ALPHA_FACTOR_INTERPOLATOR =
|
private static final Interpolator ALPHA_FACTOR_INTERPOLATOR =
|
||||||
(t) -> (t < 0.8f) ? 0 : (t - 0.8f) / 0.2f;
|
(t) -> (t < 0.8f) ? 0 : (t - 0.8f) / 0.2f;
|
||||||
|
|
||||||
private static final OnClickListener PREDICTION_CLICK_LISTENER =
|
|
||||||
ItemClickHandler.getInstance(AppLaunchTracker.CONTAINER_PREDICTIONS);
|
|
||||||
|
|
||||||
private final Launcher mLauncher;
|
private final Launcher mLauncher;
|
||||||
private final PredictionUiStateManager mPredictionUiStateManager;
|
private final PredictionUiStateManager mPredictionUiStateManager;
|
||||||
private int mNumPredictedAppsPerRow;
|
private int mNumPredictedAppsPerRow;
|
||||||
|
@ -246,7 +242,7 @@ public class PredictionRowView extends LinearLayout implements
|
||||||
while (getChildCount() < mNumPredictedAppsPerRow) {
|
while (getChildCount() < mNumPredictedAppsPerRow) {
|
||||||
BubbleTextView icon = (BubbleTextView) inflater.inflate(
|
BubbleTextView icon = (BubbleTextView) inflater.inflate(
|
||||||
R.layout.all_apps_icon, this, false);
|
R.layout.all_apps_icon, this, false);
|
||||||
icon.setOnClickListener(PREDICTION_CLICK_LISTENER);
|
icon.setOnClickListener(ItemClickHandler.INSTANCE);
|
||||||
icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS);
|
icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS);
|
||||||
icon.setLongPressTimeoutFactor(1f);
|
icon.setLongPressTimeoutFactor(1f);
|
||||||
icon.setOnFocusChangeListener(mFocusHelper);
|
icon.setOnFocusChangeListener(mFocusHelper);
|
||||||
|
|
|
@ -75,8 +75,7 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||||
|
|
||||||
// TODO (b/129421797): Update the client constants
|
// TODO (b/129421797): Update the client constants
|
||||||
public enum Client {
|
public enum Client {
|
||||||
HOME("home"),
|
HOME("home");
|
||||||
OVERVIEW("overview");
|
|
||||||
|
|
||||||
public final String id;
|
public final String id;
|
||||||
|
|
||||||
|
@ -91,10 +90,9 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
|
||||||
private final DynamicItemCache mDynamicItemCache;
|
private final DynamicItemCache mDynamicItemCache;
|
||||||
private final List[] mPredictionServicePredictions;
|
private List mPredictionServicePredictions = Collections.emptyList();
|
||||||
|
|
||||||
private int mMaxIconsPerRow;
|
private int mMaxIconsPerRow;
|
||||||
private Client mActiveClient;
|
|
||||||
|
|
||||||
private AllAppsContainerView mAppsView;
|
private AllAppsContainerView mAppsView;
|
||||||
|
|
||||||
|
@ -108,16 +106,10 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||||
|
|
||||||
mDynamicItemCache = new DynamicItemCache(context, this::onAppsUpdated);
|
mDynamicItemCache = new DynamicItemCache(context, this::onAppsUpdated);
|
||||||
|
|
||||||
mActiveClient = Client.HOME;
|
|
||||||
|
|
||||||
InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
|
InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
|
||||||
mMaxIconsPerRow = idp.numColumns;
|
mMaxIconsPerRow = idp.numColumns;
|
||||||
|
|
||||||
idp.addOnChangeListener(this);
|
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)
|
mGettingValidPredictionResults = Utilities.getDevicePrefs(context)
|
||||||
.getBoolean(LAST_PREDICTION_ENABLED_STATE, true);
|
.getBoolean(LAST_PREDICTION_ENABLED_STATE, true);
|
||||||
|
|
||||||
|
@ -130,18 +122,6 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||||
mMaxIconsPerRow = profile.numColumns;
|
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) {
|
public void setTargetAppsView(AllAppsContainerView appsView) {
|
||||||
if (mAppsView != null) {
|
if (mAppsView != null) {
|
||||||
mAppsView.getAppsStore().removeUpdateListener(this);
|
mAppsView.getAppsStore().removeUpdateListener(this);
|
||||||
|
@ -195,10 +175,8 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePredictionStateAfterCallback() {
|
private void updatePredictionStateAfterCallback() {
|
||||||
boolean validResults = false;
|
boolean validResults = mPredictionServicePredictions != null
|
||||||
for (List l : mPredictionServicePredictions) {
|
&& !mPredictionServicePredictions.isEmpty();
|
||||||
validResults |= l != null && !l.isEmpty();
|
|
||||||
}
|
|
||||||
if (validResults != mGettingValidPredictionResults) {
|
if (validResults != mGettingValidPredictionResults) {
|
||||||
mGettingValidPredictionResults = validResults;
|
mGettingValidPredictionResults = validResults;
|
||||||
Utilities.getDevicePrefs(mContext).edit()
|
Utilities.getDevicePrefs(mContext).edit()
|
||||||
|
@ -210,7 +188,7 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||||
|
|
||||||
public AppPredictor.Callback appPredictorCallback(Client client) {
|
public AppPredictor.Callback appPredictorCallback(Client client) {
|
||||||
return targets -> {
|
return targets -> {
|
||||||
mPredictionServicePredictions[client.ordinal()] = targets;
|
mPredictionServicePredictions = targets;
|
||||||
updatePredictionStateAfterCallback();
|
updatePredictionStateAfterCallback();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -238,7 +216,7 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
||||||
|
|
||||||
state.apps = new ArrayList<>();
|
state.apps = new ArrayList<>();
|
||||||
|
|
||||||
List<AppTarget> appTargets = mPredictionServicePredictions[mActiveClient.ordinal()];
|
List<AppTarget> appTargets = mPredictionServicePredictions;
|
||||||
if (!appTargets.isEmpty()) {
|
if (!appTargets.isEmpty()) {
|
||||||
for (AppTarget appTarget : appTargets) {
|
for (AppTarget appTarget : appTargets) {
|
||||||
ComponentKey key;
|
ComponentKey key;
|
||||||
|
|
|
@ -34,8 +34,6 @@ import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.android.launcher3.BaseQuickstepLauncher;
|
import com.android.launcher3.BaseQuickstepLauncher;
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.Launcher;
|
import com.android.launcher3.Launcher;
|
||||||
|
@ -129,12 +127,11 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean startActivitySafely(View v, Intent intent, ItemInfo item,
|
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
|
||||||
@Nullable String sourceContainer) {
|
|
||||||
if (mHotseatPredictionController != null) {
|
if (mHotseatPredictionController != null) {
|
||||||
mHotseatPredictionController.setPauseUIUpdate(true);
|
mHotseatPredictionController.setPauseUIUpdate(true);
|
||||||
}
|
}
|
||||||
return super.startActivitySafely(v, intent, item, sourceContainer);
|
return super.startActivitySafely(v, intent, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -24,6 +24,7 @@ import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MOD
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorSet;
|
import android.animation.AnimatorSet;
|
||||||
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
|
@ -52,17 +53,17 @@ final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extend
|
||||||
|
|
||||||
private final BaseActivityInterface<?, T> mActivityInterface;
|
private final BaseActivityInterface<?, T> mActivityInterface;
|
||||||
// The id of the currently running task that is transitioning to overview.
|
// 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 final RecentsAnimationDeviceState mDeviceState;
|
||||||
|
|
||||||
private T mActivity;
|
private T mActivity;
|
||||||
private RecentsView mRecentsView;
|
private RecentsView mRecentsView;
|
||||||
|
|
||||||
AppToOverviewAnimationProvider(
|
AppToOverviewAnimationProvider(
|
||||||
BaseActivityInterface<?, T> activityInterface, int targetTaskId,
|
BaseActivityInterface<?, T> activityInterface, RunningTaskInfo targetTask,
|
||||||
RecentsAnimationDeviceState deviceState) {
|
RecentsAnimationDeviceState deviceState) {
|
||||||
mActivityInterface = activityInterface;
|
mActivityInterface = activityInterface;
|
||||||
mTargetTaskId = targetTaskId;
|
mTargetTask = targetTask;
|
||||||
mDeviceState = deviceState;
|
mDeviceState = deviceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +74,7 @@ final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extend
|
||||||
* @param wasVisible true if it was visible before
|
* @param wasVisible true if it was visible before
|
||||||
*/
|
*/
|
||||||
boolean onActivityReady(T activity, Boolean wasVisible) {
|
boolean onActivityReady(T activity, Boolean wasVisible) {
|
||||||
activity.<RecentsView>getOverviewPanel().showCurrentTask(mTargetTaskId);
|
activity.<RecentsView>getOverviewPanel().showCurrentTask(mTargetTask);
|
||||||
AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
|
AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
|
||||||
BaseActivityInterface.AnimationFactory factory = mActivityInterface.prepareRecentsUI(
|
BaseActivityInterface.AnimationFactory factory = mActivityInterface.prepareRecentsUI(
|
||||||
mDeviceState,
|
mDeviceState,
|
||||||
|
@ -122,7 +123,8 @@ final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extend
|
||||||
wallpaperTargets, MODE_CLOSING);
|
wallpaperTargets, MODE_CLOSING);
|
||||||
|
|
||||||
// Use the top closing app to determine the insets for the animation
|
// 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) {
|
if (runningTaskTarget == null) {
|
||||||
Log.e(TAG, "No closing app");
|
Log.e(TAG, "No closing app");
|
||||||
return pa.buildAnim();
|
return pa.buildAnim();
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package com.android.quickstep;
|
package com.android.quickstep;
|
||||||
|
|
||||||
|
import static android.widget.Toast.LENGTH_SHORT;
|
||||||
|
|
||||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||||
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||||
|
@ -27,11 +29,13 @@ import android.graphics.Rect;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.statemanager.StatefulActivity;
|
import com.android.launcher3.statemanager.StatefulActivity;
|
||||||
import com.android.launcher3.testing.TestProtocol;
|
import com.android.launcher3.testing.TestProtocol;
|
||||||
import com.android.launcher3.util.VibratorWrapper;
|
import com.android.launcher3.util.VibratorWrapper;
|
||||||
|
@ -138,10 +142,10 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
|
||||||
mRecentsView.getNextPageTaskView().launchTask(false /* animate */,
|
mRecentsView.getNextPageTaskView().launchTask(false /* animate */,
|
||||||
true /* freezeTaskList */);
|
true /* freezeTaskList */);
|
||||||
} else {
|
} else {
|
||||||
int taskId = mRecentsView.getNextPageTaskView().getTask().key.id;
|
|
||||||
if (!mCanceled) {
|
if (!mCanceled) {
|
||||||
TaskView nextTask = mRecentsView.getTaskView(taskId);
|
TaskView nextTask = mRecentsView.getNextPageTaskView();
|
||||||
if (nextTask != null) {
|
if (nextTask != null) {
|
||||||
|
int taskId = nextTask.getTask().key.id;
|
||||||
mGestureState.updateLastStartedTaskId(taskId);
|
mGestureState.updateLastStartedTaskId(taskId);
|
||||||
boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds()
|
boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds()
|
||||||
.contains(taskId);
|
.contains(taskId);
|
||||||
|
@ -158,6 +162,10 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
|
||||||
mRecentsAnimationController.finish(true /* toRecents */, null);
|
mRecentsAnimationController.finish(true /* toRecents */, null);
|
||||||
}
|
}
|
||||||
}, MAIN_EXECUTOR.getHandler());
|
}, MAIN_EXECUTOR.getHandler());
|
||||||
|
} else {
|
||||||
|
mActivityInterface.onLaunchTaskFailed();
|
||||||
|
Toast.makeText(mContext, R.string.activity_not_available, LENGTH_SHORT).show();
|
||||||
|
mRecentsAnimationController.finish(true /* toRecents */, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mCanceled = false;
|
mCanceled = false;
|
||||||
|
|
|
@ -38,7 +38,6 @@ import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINI
|
||||||
import static com.android.quickstep.GestureState.STATE_END_TARGET_SET;
|
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.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
|
||||||
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
|
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.HIDE;
|
||||||
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK;
|
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK;
|
||||||
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
|
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||||
|
@ -60,6 +59,7 @@ import android.view.ViewTreeObserver.OnDrawListener;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
import com.android.launcher3.AbstractFloatingView;
|
import com.android.launcher3.AbstractFloatingView;
|
||||||
|
@ -70,6 +70,7 @@ import com.android.launcher3.anim.AnimationSuccessListener;
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
import com.android.launcher3.anim.Interpolators;
|
import com.android.launcher3.anim.Interpolators;
|
||||||
import com.android.launcher3.logging.StatsLogManager;
|
import com.android.launcher3.logging.StatsLogManager;
|
||||||
|
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
|
||||||
import com.android.launcher3.logging.UserEventDispatcher;
|
import com.android.launcher3.logging.UserEventDispatcher;
|
||||||
import com.android.launcher3.statemanager.StatefulActivity;
|
import com.android.launcher3.statemanager.StatefulActivity;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||||
|
@ -266,10 +267,6 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK,
|
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK,
|
||||||
this::notifyTransitionCancelled);
|
this::notifyTransitionCancelled);
|
||||||
|
|
||||||
mGestureState.runOnceAtState(STATE_END_TARGET_SET,
|
|
||||||
() -> mDeviceState.onEndTargetCalculated(mGestureState.getEndTarget(),
|
|
||||||
mActivityInterface));
|
|
||||||
|
|
||||||
if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||||
mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
|
mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
|
||||||
| STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT,
|
| STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT,
|
||||||
|
@ -313,12 +310,6 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
}
|
}
|
||||||
|
|
||||||
setupRecentsViewUi();
|
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();
|
linkRecentsViewScroll();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -400,6 +391,11 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
mGestureState.getActivityInterface().setOnDeferredActivityLaunchCallback(
|
mGestureState.getActivityInterface().setOnDeferredActivityLaunchCallback(
|
||||||
mOnDeferredActivityLaunch);
|
mOnDeferredActivityLaunch);
|
||||||
|
|
||||||
|
mGestureState.runOnceAtState(STATE_END_TARGET_SET,
|
||||||
|
() -> mDeviceState.getRotationTouchHelper().
|
||||||
|
onEndTargetCalculated(mGestureState.getEndTarget(),
|
||||||
|
mActivityInterface));
|
||||||
|
|
||||||
notifyGestureStartedAsync();
|
notifyGestureStartedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,7 +419,7 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void notifyGestureAnimationStartToRecents() {
|
protected void notifyGestureAnimationStartToRecents() {
|
||||||
mRecentsView.onGestureAnimationStart(mGestureState.getRunningTaskId());
|
mRecentsView.onGestureAnimationStart(mGestureState.getRunningTask());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void launcherFrameDrawn() {
|
private void launcherFrameDrawn() {
|
||||||
|
@ -451,12 +447,6 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
@Override
|
@Override
|
||||||
public void onMotionPauseChanged(boolean isPaused) {
|
public void onMotionPauseChanged(boolean isPaused) {
|
||||||
setShelfState(isPaused ? PEEK : HIDE, ShelfPeekAnim.INTERPOLATOR, ShelfPeekAnim.DURATION);
|
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() {
|
public void maybeUpdateRecentsAttachedState() {
|
||||||
|
@ -555,14 +545,6 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateFinalShift() {
|
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;
|
final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW;
|
||||||
if (passed != mPassedOverviewThreshold) {
|
if (passed != mPassedOverviewThreshold) {
|
||||||
mPassedOverviewThreshold = passed;
|
mPassedOverviewThreshold = passed;
|
||||||
|
@ -573,6 +555,14 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
|
|
||||||
updateSysUiFlags(mCurrentShift.value);
|
updateSysUiFlags(mCurrentShift.value);
|
||||||
applyWindowTransform();
|
applyWindowTransform();
|
||||||
|
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||||
|
if (mRecentsAnimationTargets != null) {
|
||||||
|
LiveTileOverlay.INSTANCE.update(
|
||||||
|
mTaskViewSimulator.getCurrentRect(),
|
||||||
|
mTaskViewSimulator.getCurrentCornerRadius());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateLauncherTransitionProgress();
|
updateLauncherTransitionProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -889,22 +879,7 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs);
|
animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doLogGesture(GestureEndTarget endTarget) {
|
private void doLogGesture(GestureEndTarget endTarget, @Nullable TaskView targetTask) {
|
||||||
DeviceProfile dp = mDp;
|
|
||||||
if (dp == null || mDownPos == null) {
|
|
||||||
// We probably never received an animation controller, skip logging.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pageIndex = endTarget == LAST_TASK
|
|
||||||
? LOG_NO_OP_PAGE_INDEX
|
|
||||||
: mRecentsView.getNextPage();
|
|
||||||
UserEventDispatcher.newInstance(mContext).logStateChangeAction(
|
|
||||||
mLogAction, mLogDirection,
|
|
||||||
(int) mDownPos.x, (int) mDownPos.y,
|
|
||||||
ContainerType.NAVBAR, ContainerType.APP,
|
|
||||||
endTarget.containerType,
|
|
||||||
pageIndex);
|
|
||||||
StatsLogManager.EventEnum event;
|
StatsLogManager.EventEnum event;
|
||||||
switch (endTarget) {
|
switch (endTarget) {
|
||||||
case HOME:
|
case HOME:
|
||||||
|
@ -922,10 +897,29 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
default:
|
default:
|
||||||
event = IGNORE;
|
event = IGNORE;
|
||||||
}
|
}
|
||||||
StatsLogManager.newInstance(mContext).logger()
|
StatsLogger logger = StatsLogManager.newInstance(mContext).logger()
|
||||||
.withSrcState(LAUNCHER_STATE_BACKGROUND)
|
.withSrcState(LAUNCHER_STATE_BACKGROUND)
|
||||||
.withDstState(StatsLogManager.containerTypeToAtomState(endTarget.containerType))
|
.withDstState(StatsLogManager.containerTypeToAtomState(endTarget.containerType));
|
||||||
.log(event);
|
if (targetTask != null) {
|
||||||
|
logger.withItemInfo(targetTask.getItemInfo());
|
||||||
|
}
|
||||||
|
logger.log(event);
|
||||||
|
|
||||||
|
|
||||||
|
DeviceProfile dp = mDp;
|
||||||
|
if (dp == null || mDownPos == null) {
|
||||||
|
// We probably never received an animation controller, skip logging.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int pageIndex = endTarget == LAST_TASK
|
||||||
|
? LOG_NO_OP_PAGE_INDEX
|
||||||
|
: mRecentsView.getNextPage();
|
||||||
|
UserEventDispatcher.newInstance(mContext).logStateChangeAction(
|
||||||
|
mLogAction, mLogDirection,
|
||||||
|
(int) mDownPos.x, (int) mDownPos.y,
|
||||||
|
ContainerType.NAVBAR, ContainerType.APP,
|
||||||
|
endTarget.containerType,
|
||||||
|
pageIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
|
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
|
||||||
|
@ -1130,7 +1124,7 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
private void resumeLastTask() {
|
private void resumeLastTask() {
|
||||||
mRecentsAnimationController.finish(false /* toRecents */, null);
|
mRecentsAnimationController.finish(false /* toRecents */, null);
|
||||||
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
|
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
|
||||||
doLogGesture(LAST_TASK);
|
doLogGesture(LAST_TASK, null);
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1145,6 +1139,7 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void startNewTaskInternal() {
|
private void startNewTaskInternal() {
|
||||||
|
TaskView taskToLaunch = mRecentsView == null ? null : mRecentsView.getNextPageTaskView();
|
||||||
startNewTask(success -> {
|
startNewTask(success -> {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
reset();
|
reset();
|
||||||
|
@ -1153,7 +1148,7 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
endLauncherTransitionController();
|
endLauncherTransitionController();
|
||||||
updateSysUiFlags(1 /* windowProgress == overview */);
|
updateSysUiFlags(1 /* windowProgress == overview */);
|
||||||
}
|
}
|
||||||
doLogGesture(NEW_TASK);
|
doLogGesture(NEW_TASK, taskToLaunch);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1298,7 +1293,7 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
() -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
|
() -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
|
||||||
}
|
}
|
||||||
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
|
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
|
||||||
doLogGesture(HOME);
|
doLogGesture(HOME, mRecentsView == null ? null : mRecentsView.getCurrentPageTaskView());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void finishRecentsControllerToHome(Runnable callback);
|
protected abstract void finishRecentsControllerToHome(Runnable callback);
|
||||||
|
@ -1313,7 +1308,7 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
||||||
mRecentsView.onSwipeUpAnimationSuccess();
|
mRecentsView.onSwipeUpAnimationSuccess();
|
||||||
|
|
||||||
SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
|
SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
|
||||||
doLogGesture(RECENTS);
|
doLogGesture(RECENTS, mRecentsView.getCurrentPageTaskView());
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ public final class FallbackActivityInterface extends
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExitOverview(RecentsAnimationDeviceState deviceState, Runnable exitRunnable) {
|
public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) {
|
||||||
// no-op, fake landscape not supported for 3P
|
// no-op, fake landscape not supported for 3P
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,6 @@ public class FallbackSwipeHandler extends
|
||||||
|
|
||||||
private final long mDuration;
|
private final long mDuration;
|
||||||
FallbackHomeAnimationFactory(long duration) {
|
FallbackHomeAnimationFactory(long duration) {
|
||||||
super(null);
|
|
||||||
mDuration = duration;
|
mDuration = duration;
|
||||||
|
|
||||||
if (mRunningOverHome) {
|
if (mRunningOverHome) {
|
||||||
|
|
|
@ -105,7 +105,7 @@ public final class LauncherActivityInterface extends
|
||||||
// recents, we assume the first task is invisible, making translation off by one task.
|
// recents, we assume the first task is invisible, making translation off by one task.
|
||||||
launcher.getStateManager().reapplyState();
|
launcher.getStateManager().reapplyState();
|
||||||
launcher.getRootView().setForceHideBackArrow(false);
|
launcher.getRootView().setForceHideBackArrow(false);
|
||||||
notifyRecentsOfOrientation(deviceState);
|
notifyRecentsOfOrientation(deviceState.getRotationTouchHelper());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -120,7 +120,7 @@ public final class LauncherActivityInterface extends
|
||||||
@Override
|
@Override
|
||||||
public AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
|
public AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
|
||||||
boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
|
boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
|
||||||
notifyRecentsOfOrientation(deviceState);
|
notifyRecentsOfOrientation(deviceState.getRotationTouchHelper());
|
||||||
DefaultAnimationFactory factory = new DefaultAnimationFactory(callback) {
|
DefaultAnimationFactory factory = new DefaultAnimationFactory(callback) {
|
||||||
@Override
|
@Override
|
||||||
public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator,
|
public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator,
|
||||||
|
@ -228,7 +228,7 @@ public final class LauncherActivityInterface extends
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExitOverview(RecentsAnimationDeviceState deviceState, Runnable exitRunnable) {
|
public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) {
|
||||||
final StateManager<LauncherState> stateManager = getCreatedActivity().getStateManager();
|
final StateManager<LauncherState> stateManager = getCreatedActivity().getStateManager();
|
||||||
stateManager.addStateListener(
|
stateManager.addStateListener(
|
||||||
new StateManager.StateListener<LauncherState>() {
|
new StateManager.StateListener<LauncherState>() {
|
||||||
|
@ -244,11 +244,11 @@ public final class LauncherActivityInterface extends
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyRecentsOfOrientation(RecentsAnimationDeviceState deviceState) {
|
private void notifyRecentsOfOrientation(RotationTouchHelper rotationTouchHelper) {
|
||||||
// reset layout on swipe to home
|
// reset layout on swipe to home
|
||||||
RecentsView recentsView = getCreatedActivity().getOverviewPanel();
|
RecentsView recentsView = getCreatedActivity().getOverviewPanel();
|
||||||
recentsView.setLayoutRotation(deviceState.getCurrentActiveRotation(),
|
recentsView.setLayoutRotation(rotationTouchHelper.getCurrentActiveRotation(),
|
||||||
deviceState.getDisplayRotation());
|
rotationTouchHelper.getDisplayRotation());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -261,16 +261,6 @@ public final class LauncherActivityInterface extends
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateOverviewPredictionState() {
|
|
||||||
Launcher launcher = getCreatedActivity();
|
|
||||||
if (launcher == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PredictionUiStateManager.INSTANCE.get(launcher).switchClient(
|
|
||||||
PredictionUiStateManager.Client.OVERVIEW);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getContainerType() {
|
public int getContainerType() {
|
||||||
final Launcher launcher = getVisibleLauncher();
|
final Launcher launcher = getVisibleLauncher();
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package com.android.quickstep;
|
package com.android.quickstep;
|
||||||
|
|
||||||
import static com.android.launcher3.LauncherState.NORMAL;
|
import static com.android.launcher3.LauncherState.NORMAL;
|
||||||
|
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
|
||||||
|
|
||||||
import android.animation.AnimatorSet;
|
import android.animation.AnimatorSet;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -28,6 +29,7 @@ import androidx.annotation.NonNull;
|
||||||
import com.android.launcher3.BaseQuickstepLauncher;
|
import com.android.launcher3.BaseQuickstepLauncher;
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
import com.android.launcher3.views.FloatingIconView;
|
import com.android.launcher3.views.FloatingIconView;
|
||||||
|
import com.android.quickstep.util.RectFSpringAnim;
|
||||||
import com.android.quickstep.util.StaggeredWorkspaceAnim;
|
import com.android.quickstep.util.StaggeredWorkspaceAnim;
|
||||||
import com.android.quickstep.views.RecentsView;
|
import com.android.quickstep.views.RecentsView;
|
||||||
import com.android.quickstep.views.TaskView;
|
import com.android.quickstep.views.TaskView;
|
||||||
|
@ -72,36 +74,39 @@ public class LauncherSwipeHandlerV2 extends
|
||||||
mActivity.getRootView().setForceHideBackArrow(true);
|
mActivity.getRootView().setForceHideBackArrow(true);
|
||||||
mActivity.setHintUserWillBeActive();
|
mActivity.setHintUserWillBeActive();
|
||||||
|
|
||||||
homeAnimFactory = new HomeAnimationFactory(floatingIconView) {
|
if (canUseWorkspaceView) {
|
||||||
|
// We want the window alpha to be 0 once this threshold is met, so that the
|
||||||
@Override
|
// FolderIconView can be seen morphing into the icon shape.
|
||||||
public RectF getWindowTargetRect() {
|
float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
|
||||||
if (canUseWorkspaceView) {
|
homeAnimFactory = new LauncherHomeAnimationFactory() {
|
||||||
|
@Override
|
||||||
|
public RectF getWindowTargetRect() {
|
||||||
return iconLocation;
|
return iconLocation;
|
||||||
} else {
|
|
||||||
return super.getWindowTargetRect();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@Override
|
||||||
@Override
|
public void setAnimation(RectFSpringAnim anim) {
|
||||||
public AnimatorPlaybackController createActivityAnimationToHome() {
|
anim.addAnimatorListener(floatingIconView);
|
||||||
// Return an empty APC here since we have an non-user controlled animation
|
floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged);
|
||||||
// to home.
|
floatingIconView.setFastFinishRunnable(anim::end);
|
||||||
long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
|
}
|
||||||
return mActivity.getStateManager().createAnimationToNewWorkspace(
|
|
||||||
NORMAL, accuracy, 0 /* animComponents */);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void playAtomicAnimation(float velocity) {
|
public void update(RectF currentRect, float progress, float radius) {
|
||||||
new StaggeredWorkspaceAnim(mActivity, velocity,
|
floatingIconView.update(currentRect, 1f, progress, windowAlphaThreshold,
|
||||||
true /* animateOverviewScrim */).start();
|
radius, false);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancel() {
|
||||||
|
floatingIconView.fastFinish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
homeAnimFactory = new LauncherHomeAnimationFactory();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
homeAnimFactory = new HomeAnimationFactory(null) {
|
homeAnimFactory = new HomeAnimationFactory() {
|
||||||
@Override
|
@Override
|
||||||
public AnimatorPlaybackController createActivityAnimationToHome() {
|
public AnimatorPlaybackController createActivityAnimationToHome() {
|
||||||
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
|
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
|
||||||
|
@ -118,4 +123,22 @@ public class LauncherSwipeHandlerV2 extends
|
||||||
mRecentsAnimationController.finish(
|
mRecentsAnimationController.finish(
|
||||||
true /* toRecents */, callback, true /* sendUserLeaveHint */);
|
true /* toRecents */, callback, true /* sendUserLeaveHint */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class LauncherHomeAnimationFactory extends HomeAnimationFactory {
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public AnimatorPlaybackController createActivityAnimationToHome() {
|
||||||
|
// Return an empty APC here since we have an non-user controlled animation
|
||||||
|
// to home.
|
||||||
|
long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
|
||||||
|
return mActivity.getStateManager().createAnimationToNewWorkspace(
|
||||||
|
NORMAL, accuracy, 0 /* animComponents */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void playAtomicAnimation(float velocity) {
|
||||||
|
new StaggeredWorkspaceAnim(mActivity, velocity,
|
||||||
|
true /* animateOverviewScrim */).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ import android.view.ViewConfiguration;
|
||||||
|
|
||||||
import androidx.annotation.BinderThread;
|
import androidx.annotation.BinderThread;
|
||||||
|
|
||||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
|
||||||
import com.android.launcher3.logging.UserEventDispatcher;
|
import com.android.launcher3.logging.UserEventDispatcher;
|
||||||
import com.android.launcher3.statemanager.StatefulActivity;
|
import com.android.launcher3.statemanager.StatefulActivity;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||||
|
@ -165,7 +164,7 @@ public class OverviewCommandHelper {
|
||||||
mActivityInterface = mOverviewComponentObserver.getActivityInterface();
|
mActivityInterface = mOverviewComponentObserver.getActivityInterface();
|
||||||
mCreateTime = SystemClock.elapsedRealtime();
|
mCreateTime = SystemClock.elapsedRealtime();
|
||||||
mAnimationProvider = new AppToOverviewAnimationProvider<>(mActivityInterface,
|
mAnimationProvider = new AppToOverviewAnimationProvider<>(mActivityInterface,
|
||||||
RecentsModel.getRunningTaskId(), mDeviceState);
|
ActivityManagerWrapper.getInstance().getRunningTask(), mDeviceState);
|
||||||
|
|
||||||
// Preload the plan
|
// Preload the plan
|
||||||
mRecentsModel.getTasks(null);
|
mRecentsModel.getTasks(null);
|
||||||
|
@ -227,10 +226,6 @@ public class OverviewCommandHelper {
|
||||||
LauncherLogProto.ContainerType.TASKSWITCHER);
|
LauncherLogProto.ContainerType.TASKSWITCHER);
|
||||||
mUserEventLogged = true;
|
mUserEventLogged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch prediction client to overview
|
|
||||||
PredictionUiStateManager.INSTANCE.get(activity).switchClient(
|
|
||||||
PredictionUiStateManager.Client.OVERVIEW);
|
|
||||||
return mAnimationProvider.onActivityReady(activity, wasVisible);
|
return mAnimationProvider.onActivityReady(activity, wasVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ package com.android.quickstep;
|
||||||
|
|
||||||
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
|
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
|
||||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||||
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
|
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -28,7 +27,6 @@ import android.graphics.RectF;
|
||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
|
@ -37,7 +35,6 @@ import com.android.launcher3.anim.AnimationSuccessListener;
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
import com.android.launcher3.anim.PendingAnimation;
|
import com.android.launcher3.anim.PendingAnimation;
|
||||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||||
import com.android.launcher3.views.FloatingIconView;
|
|
||||||
import com.android.quickstep.util.RectFSpringAnim;
|
import com.android.quickstep.util.RectFSpringAnim;
|
||||||
import com.android.quickstep.util.TaskViewSimulator;
|
import com.android.quickstep.util.TaskViewSimulator;
|
||||||
import com.android.quickstep.util.TransformParams;
|
import com.android.quickstep.util.TransformParams;
|
||||||
|
@ -85,7 +82,8 @@ public abstract class SwipeUpAnimationLogic {
|
||||||
mTransformParams = transformParams;
|
mTransformParams = transformParams;
|
||||||
|
|
||||||
mTaskViewSimulator.setLayoutRotation(
|
mTaskViewSimulator.setLayoutRotation(
|
||||||
mDeviceState.getCurrentActiveRotation(), mDeviceState.getDisplayRotation());
|
mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(),
|
||||||
|
mDeviceState.getRotationTouchHelper().getDisplayRotation());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initTransitionEndpoints(DeviceProfile dp) {
|
protected void initTransitionEndpoints(DeviceProfile dp) {
|
||||||
|
@ -148,12 +146,6 @@ public abstract class SwipeUpAnimationLogic {
|
||||||
|
|
||||||
protected abstract class HomeAnimationFactory {
|
protected abstract class HomeAnimationFactory {
|
||||||
|
|
||||||
public FloatingIconView mIconView;
|
|
||||||
|
|
||||||
public HomeAnimationFactory(@Nullable FloatingIconView iconView) {
|
|
||||||
mIconView = iconView;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull RectF getWindowTargetRect() {
|
public @NonNull RectF getWindowTargetRect() {
|
||||||
PagedOrientationHandler orientationHandler = getOrientationHandler();
|
PagedOrientationHandler orientationHandler = getOrientationHandler();
|
||||||
DeviceProfile dp = mDp;
|
DeviceProfile dp = mDp;
|
||||||
|
@ -174,6 +166,12 @@ public abstract class SwipeUpAnimationLogic {
|
||||||
public void playAtomicAnimation(float velocity) {
|
public void playAtomicAnimation(float velocity) {
|
||||||
// No-op
|
// No-op
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAnimation(RectFSpringAnim anim) { }
|
||||||
|
|
||||||
|
public void update(RectF currentRect, float progress, float radius) { }
|
||||||
|
|
||||||
|
public void onCancel() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -184,8 +182,6 @@ public abstract class SwipeUpAnimationLogic {
|
||||||
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
|
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
|
||||||
HomeAnimationFactory homeAnimationFactory) {
|
HomeAnimationFactory homeAnimationFactory) {
|
||||||
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
|
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
|
||||||
final FloatingIconView fiv = homeAnimationFactory.mIconView;
|
|
||||||
final boolean isFloatingIconView = fiv != null;
|
|
||||||
|
|
||||||
mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor);
|
mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor);
|
||||||
mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress));
|
mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress));
|
||||||
|
@ -203,11 +199,7 @@ public abstract class SwipeUpAnimationLogic {
|
||||||
windowToHomePositionMap.mapRect(startRect);
|
windowToHomePositionMap.mapRect(startRect);
|
||||||
|
|
||||||
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext);
|
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext);
|
||||||
if (isFloatingIconView) {
|
homeAnimationFactory.setAnimation(anim);
|
||||||
anim.addAnimatorListener(fiv);
|
|
||||||
fiv.setOnTargetChangeListener(anim::onTargetPositionChanged);
|
|
||||||
fiv.setFastFinishRunnable(anim::end);
|
|
||||||
}
|
|
||||||
|
|
||||||
SpringAnimationRunner runner = new SpringAnimationRunner(
|
SpringAnimationRunner runner = new SpringAnimationRunner(
|
||||||
homeAnimationFactory, cropRectF, homeToWindowPositionMap);
|
homeAnimationFactory, cropRectF, homeToWindowPositionMap);
|
||||||
|
@ -242,32 +234,27 @@ public abstract class SwipeUpAnimationLogic {
|
||||||
|
|
||||||
final RectF mWindowCurrentRect = new RectF();
|
final RectF mWindowCurrentRect = new RectF();
|
||||||
final Matrix mHomeToWindowPositionMap;
|
final Matrix mHomeToWindowPositionMap;
|
||||||
|
final HomeAnimationFactory mAnimationFactory;
|
||||||
|
|
||||||
final FloatingIconView mFIV;
|
|
||||||
final AnimatorPlaybackController mHomeAnim;
|
final AnimatorPlaybackController mHomeAnim;
|
||||||
final RectF mCropRectF;
|
final RectF mCropRectF;
|
||||||
|
|
||||||
final float mStartRadius;
|
final float mStartRadius;
|
||||||
final float mEndRadius;
|
final float mEndRadius;
|
||||||
final float mWindowAlphaThreshold;
|
|
||||||
|
|
||||||
SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF,
|
SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF,
|
||||||
Matrix homeToWindowPositionMap) {
|
Matrix homeToWindowPositionMap) {
|
||||||
|
mAnimationFactory = factory;
|
||||||
mHomeAnim = factory.createActivityAnimationToHome();
|
mHomeAnim = factory.createActivityAnimationToHome();
|
||||||
mCropRectF = cropRectF;
|
mCropRectF = cropRectF;
|
||||||
mHomeToWindowPositionMap = homeToWindowPositionMap;
|
mHomeToWindowPositionMap = homeToWindowPositionMap;
|
||||||
|
|
||||||
cropRectF.roundOut(mCropRect);
|
cropRectF.roundOut(mCropRect);
|
||||||
mFIV = factory.mIconView;
|
|
||||||
|
|
||||||
// End on a "round-enough" radius so that the shape reveal doesn't have to do too much
|
// End on a "round-enough" radius so that the shape reveal doesn't have to do too much
|
||||||
// rounding at the end of the animation.
|
// rounding at the end of the animation.
|
||||||
mStartRadius = mTaskViewSimulator.getCurrentCornerRadius();
|
mStartRadius = mTaskViewSimulator.getCurrentCornerRadius();
|
||||||
mEndRadius = cropRectF.width() / 2f;
|
mEndRadius = cropRectF.width() / 2f;
|
||||||
|
|
||||||
// We want the window alpha to be 0 once this threshold is met, so that the
|
|
||||||
// FolderIconView can be seen morphing into the icon shape.
|
|
||||||
mWindowAlphaThreshold = mFIV != null ? 1f - SHAPE_PROGRESS_DURATION : 1f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -282,10 +269,7 @@ public abstract class SwipeUpAnimationLogic {
|
||||||
.setCornerRadius(cornerRadius);
|
.setCornerRadius(cornerRadius);
|
||||||
|
|
||||||
mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
|
mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
|
||||||
if (mFIV != null) {
|
mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
|
||||||
mFIV.update(currentRect, 1f, progress,
|
|
||||||
mWindowAlphaThreshold, mMatrix.mapRadius(cornerRadius), false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -298,9 +282,7 @@ public abstract class SwipeUpAnimationLogic {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancel() {
|
public void onCancel() {
|
||||||
if (mFIV != null) {
|
mAnimationFactory.onCancel();
|
||||||
mFIV.fastFinish();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,6 +19,7 @@ package com.android.quickstep;
|
||||||
import static android.view.Surface.ROTATION_0;
|
import static android.view.Surface.ROTATION_0;
|
||||||
|
|
||||||
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
|
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
|
||||||
|
import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBNAIL;
|
||||||
import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
|
import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
@ -146,26 +147,29 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
||||||
*/
|
*/
|
||||||
public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix,
|
public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix,
|
||||||
boolean rotated) {
|
boolean rotated) {
|
||||||
final boolean isAllowedByPolicy = thumbnail.isRealSnapshot;
|
getActionsView().updateDisabledFlags(DISABLED_NO_THUMBNAIL, thumbnail == null);
|
||||||
|
|
||||||
getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated);
|
if (thumbnail != null) {
|
||||||
|
getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated);
|
||||||
|
final boolean isAllowedByPolicy = thumbnail.isRealSnapshot;
|
||||||
|
|
||||||
getActionsView().setCallbacks(new OverlayUICallbacks() {
|
getActionsView().setCallbacks(new OverlayUICallbacks() {
|
||||||
@Override
|
@Override
|
||||||
public void onShare() {
|
public void onShare() {
|
||||||
if (isAllowedByPolicy) {
|
if (isAllowedByPolicy) {
|
||||||
mImageApi.startShareActivity();
|
mImageApi.startShareActivity();
|
||||||
} else {
|
} else {
|
||||||
showBlockedByPolicyMessage();
|
showBlockedByPolicyMessage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
@Override
|
@Override
|
||||||
public void onScreenshot() {
|
public void onScreenshot() {
|
||||||
saveScreenshot(task);
|
saveScreenshot(task);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -61,7 +61,6 @@ import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
import com.android.launcher3.logging.UserEventDispatcher;
|
import com.android.launcher3.logging.UserEventDispatcher;
|
||||||
import com.android.launcher3.model.AppLaunchTracker;
|
|
||||||
import com.android.launcher3.provider.RestoreDbTask;
|
import com.android.launcher3.provider.RestoreDbTask;
|
||||||
import com.android.launcher3.statemanager.StatefulActivity;
|
import com.android.launcher3.statemanager.StatefulActivity;
|
||||||
import com.android.launcher3.testing.TestLogging;
|
import com.android.launcher3.testing.TestLogging;
|
||||||
|
@ -258,6 +257,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||||
|
|
||||||
private static boolean sConnected = false;
|
private static boolean sConnected = false;
|
||||||
private static boolean sIsInitialized = false;
|
private static boolean sIsInitialized = false;
|
||||||
|
private RotationTouchHelper mRotationTouchHelper;
|
||||||
|
|
||||||
public static boolean isConnected() {
|
public static boolean isConnected() {
|
||||||
return sConnected;
|
return sConnected;
|
||||||
|
@ -298,6 +298,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||||
mDeviceState = new RecentsAnimationDeviceState(this);
|
mDeviceState = new RecentsAnimationDeviceState(this);
|
||||||
mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
|
mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
|
||||||
mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
|
mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
|
||||||
|
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
|
||||||
ProtoTracer.INSTANCE.get(this).add(this);
|
ProtoTracer.INSTANCE.get(this).add(this);
|
||||||
|
|
||||||
sConnected = true;
|
sConnected = true;
|
||||||
|
@ -326,7 +327,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||||
mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
|
mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
|
||||||
mMainChoreographer, this::onInputEvent);
|
mMainChoreographer, this::onInputEvent);
|
||||||
|
|
||||||
mDeviceState.updateGestureTouchRegions();
|
mRotationTouchHelper.updateGestureTouchRegions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -470,9 +471,9 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||||
if (TestProtocol.sDebugTracing) {
|
if (TestProtocol.sDebugTracing) {
|
||||||
Log.d(TestProtocol.NO_SWIPE_TO_HOME, "TouchInteractionService.onInputEvent:DOWN");
|
Log.d(TestProtocol.NO_SWIPE_TO_HOME, "TouchInteractionService.onInputEvent:DOWN");
|
||||||
}
|
}
|
||||||
mDeviceState.setOrientationTransformIfNeeded(event);
|
mRotationTouchHelper.setOrientationTransformIfNeeded(event);
|
||||||
|
|
||||||
if (mDeviceState.isInSwipeUpTouchRegion(event)) {
|
if (mRotationTouchHelper.isInSwipeUpTouchRegion(event)) {
|
||||||
if (TestProtocol.sDebugTracing) {
|
if (TestProtocol.sDebugTracing) {
|
||||||
Log.d(TestProtocol.NO_SWIPE_TO_HOME,
|
Log.d(TestProtocol.NO_SWIPE_TO_HOME,
|
||||||
"TouchInteractionService.onInputEvent:isInSwipeUpTouchRegion");
|
"TouchInteractionService.onInputEvent:isInSwipeUpTouchRegion");
|
||||||
|
@ -509,7 +510,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||||
// Other events
|
// Other events
|
||||||
if (mUncheckedConsumer != InputConsumer.NO_OP) {
|
if (mUncheckedConsumer != InputConsumer.NO_OP) {
|
||||||
// Only transform the event if we are handling it in a proper consumer
|
// Only transform the event if we are handling it in a proper consumer
|
||||||
mDeviceState.setOrientationTransformIfNeeded(event);
|
mRotationTouchHelper.setOrientationTransformIfNeeded(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,7 +548,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||||
gestureState.updatePreviouslyAppearedTaskIds(
|
gestureState.updatePreviouslyAppearedTaskIds(
|
||||||
previousGestureState.getPreviouslyAppearedTaskIds());
|
previousGestureState.getPreviouslyAppearedTaskIds());
|
||||||
} else {
|
} else {
|
||||||
gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
|
gestureState.updateRunningTask(TraceHelper.allowIpcs("getRunningTask.0",
|
||||||
() -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
|
() -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
|
||||||
}
|
}
|
||||||
return gestureState;
|
return gestureState;
|
||||||
|
@ -660,7 +661,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||||
if (AssistantUtilities.isExcludedAssistant(gestureState.getRunningTask())) {
|
if (AssistantUtilities.isExcludedAssistant(gestureState.getRunningTask())) {
|
||||||
// In the case where we are in the excluded assistant state, ignore it and treat the
|
// In the case where we are in the excluded assistant state, ignore it and treat the
|
||||||
// running activity as the task behind the assistant
|
// running activity as the task behind the assistant
|
||||||
gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.assistant",
|
gestureState.updateRunningTask(TraceHelper.allowIpcs("getRunningTask.assistant",
|
||||||
() -> mAM.getRunningTask(true /* filterOnlyVisibleRecents */)));
|
() -> mAM.getRunningTask(true /* filterOnlyVisibleRecents */)));
|
||||||
ComponentName homeComponent = mOverviewComponentObserver.getHomeIntent().getComponent();
|
ComponentName homeComponent = mOverviewComponentObserver.getHomeIntent().getComponent();
|
||||||
ComponentName runningComponent =
|
ComponentName runningComponent =
|
||||||
|
@ -771,13 +772,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||||
mOverviewComponentObserver.getActivityInterface();
|
mOverviewComponentObserver.getActivityInterface();
|
||||||
final Intent overviewIntent = new Intent(
|
final Intent overviewIntent = new Intent(
|
||||||
mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState());
|
mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState());
|
||||||
if (activityInterface.getCreatedActivity() == null) {
|
if (activityInterface.getCreatedActivity() != null && fromInit) {
|
||||||
// Make sure that UI states will be initialized.
|
|
||||||
activityInterface.createActivityInitListener((wasVisible) -> {
|
|
||||||
AppLaunchTracker.INSTANCE.get(TouchInteractionService.this);
|
|
||||||
return false;
|
|
||||||
}).register(overviewIntent);
|
|
||||||
} else if (fromInit) {
|
|
||||||
// The activity has been created before the initialization of overview service. It is
|
// The activity has been created before the initialization of overview service. It is
|
||||||
// usually happens when booting or launcher is the top activity, so we should already
|
// usually happens when booting or launcher is the top activity, so we should already
|
||||||
// have the latest state.
|
// have the latest state.
|
||||||
|
|
|
@ -63,12 +63,6 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity>
|
||||||
mActivity.startHome();
|
mActivity.startHome();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldUseMultiWindowTaskSizeStrategy() {
|
|
||||||
// Just use the activity task size for multi-window as well.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When starting gesture interaction from home, we add a temporary invisible tile corresponding
|
* When starting gesture interaction from home, we add a temporary invisible tile corresponding
|
||||||
* to the home task. This allows us to handle quick-switch similarly to a quick-switching
|
* to the home task. This allows us to handle quick-switch similarly to a quick-switching
|
||||||
|
@ -76,7 +70,7 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity>
|
||||||
*/
|
*/
|
||||||
public void onGestureAnimationStartOnHome(RunningTaskInfo homeTaskInfo) {
|
public void onGestureAnimationStartOnHome(RunningTaskInfo homeTaskInfo) {
|
||||||
mHomeTaskInfo = homeTaskInfo;
|
mHomeTaskInfo = homeTaskInfo;
|
||||||
onGestureAnimationStart(homeTaskInfo == null ? -1 : homeTaskInfo.taskId);
|
onGestureAnimationStart(homeTaskInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,14 +101,15 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldAddDummyTaskView(int runningTaskId) {
|
protected boolean shouldAddDummyTaskView(RunningTaskInfo runningTaskInfo) {
|
||||||
if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == runningTaskId
|
if (mHomeTaskInfo != null && runningTaskInfo != null &&
|
||||||
|
mHomeTaskInfo.taskId == runningTaskInfo.taskId
|
||||||
&& getTaskViewCount() == 0) {
|
&& getTaskViewCount() == 0) {
|
||||||
// Do not add a dummy task if we are running over home with empty recents, so that we
|
// 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.
|
// show the empty recents message instead of showing a dummy task and later removing it.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return super.shouldAddDummyTaskView(runningTaskId);
|
return super.shouldAddDummyTaskView(runningTaskInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -99,7 +99,8 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer {
|
||||||
case ACTION_POINTER_DOWN: {
|
case ACTION_POINTER_DOWN: {
|
||||||
if (mState == STATE_INACTIVE) {
|
if (mState == STATE_INACTIVE) {
|
||||||
int pointerIndex = ev.getActionIndex();
|
int pointerIndex = ev.getActionIndex();
|
||||||
if (mDeviceState.isInSwipeUpTouchRegion(ev, pointerIndex)
|
if (mDeviceState.getRotationTouchHelper()
|
||||||
|
.isInSwipeUpTouchRegion(ev, pointerIndex)
|
||||||
&& mDelegate.allowInterceptByParent()) {
|
&& mDelegate.allowInterceptByParent()) {
|
||||||
setActive(ev);
|
setActive(ev);
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,7 @@ public class DeviceLockedInputConsumer implements InputConsumer,
|
||||||
if (!mThresholdCrossed) {
|
if (!mThresholdCrossed) {
|
||||||
// Cancel interaction in case of multi-touch interaction
|
// Cancel interaction in case of multi-touch interaction
|
||||||
int ptrIdx = ev.getActionIndex();
|
int ptrIdx = ev.getActionIndex();
|
||||||
if (!mDeviceState.isInSwipeUpTouchRegion(ev, ptrIdx)) {
|
if (!mDeviceState.getRotationTouchHelper().isInSwipeUpTouchRegion(ev, ptrIdx)) {
|
||||||
int action = ev.getAction();
|
int action = ev.getAction();
|
||||||
ev.setAction(ACTION_CANCEL);
|
ev.setAction(ACTION_CANCEL);
|
||||||
finishTouchTracking(ev);
|
finishTouchTracking(ev);
|
||||||
|
|
|
@ -59,6 +59,7 @@ import com.android.quickstep.GestureState;
|
||||||
import com.android.quickstep.InputConsumer;
|
import com.android.quickstep.InputConsumer;
|
||||||
import com.android.quickstep.RecentsAnimationCallbacks;
|
import com.android.quickstep.RecentsAnimationCallbacks;
|
||||||
import com.android.quickstep.RecentsAnimationDeviceState;
|
import com.android.quickstep.RecentsAnimationDeviceState;
|
||||||
|
import com.android.quickstep.RotationTouchHelper;
|
||||||
import com.android.quickstep.TaskAnimationManager;
|
import com.android.quickstep.TaskAnimationManager;
|
||||||
import com.android.quickstep.util.ActiveGestureLog;
|
import com.android.quickstep.util.ActiveGestureLog;
|
||||||
import com.android.quickstep.util.CachedEventDispatcher;
|
import com.android.quickstep.util.CachedEventDispatcher;
|
||||||
|
@ -86,6 +87,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||||
private final NavBarPosition mNavBarPosition;
|
private final NavBarPosition mNavBarPosition;
|
||||||
private final TaskAnimationManager mTaskAnimationManager;
|
private final TaskAnimationManager mTaskAnimationManager;
|
||||||
private final GestureState mGestureState;
|
private final GestureState mGestureState;
|
||||||
|
private final RotationTouchHelper mRotationTouchHelper;
|
||||||
private RecentsAnimationCallbacks mActiveCallbacks;
|
private RecentsAnimationCallbacks mActiveCallbacks;
|
||||||
private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher();
|
private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher();
|
||||||
private final InputMonitorCompat mInputMonitorCompat;
|
private final InputMonitorCompat mInputMonitorCompat;
|
||||||
|
@ -163,6 +165,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||||
|
|
||||||
mPassedPilferInputSlop = mPassedWindowMoveSlop = continuingPreviousGesture;
|
mPassedPilferInputSlop = mPassedWindowMoveSlop = continuingPreviousGesture;
|
||||||
mDisableHorizontalSwipe = !mPassedPilferInputSlop && disableHorizontalSwipe;
|
mDisableHorizontalSwipe = !mPassedPilferInputSlop && disableHorizontalSwipe;
|
||||||
|
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -230,7 +233,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||||
if (!mPassedPilferInputSlop) {
|
if (!mPassedPilferInputSlop) {
|
||||||
// Cancel interaction in case of multi-touch interaction
|
// Cancel interaction in case of multi-touch interaction
|
||||||
int ptrIdx = ev.getActionIndex();
|
int ptrIdx = ev.getActionIndex();
|
||||||
if (!mDeviceState.isInSwipeUpTouchRegion(ev, ptrIdx)) {
|
if (!mRotationTouchHelper.isInSwipeUpTouchRegion(ev, ptrIdx)) {
|
||||||
forceCancelGesture(ev);
|
forceCancelGesture(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -424,7 +427,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyOrientationSetup() {
|
public void notifyOrientationSetup() {
|
||||||
mDeviceState.onStartGesture();
|
mRotationTouchHelper.onStartGesture();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -205,13 +205,15 @@ public class StaggeredWorkspaceAnim {
|
||||||
ResourceProvider rp = DynamicResource.provider(v.getContext());
|
ResourceProvider rp = DynamicResource.provider(v.getContext());
|
||||||
float stiffness = rp.getFloat(R.dimen.staggered_stiffness);
|
float stiffness = rp.getFloat(R.dimen.staggered_stiffness);
|
||||||
float damping = rp.getFloat(R.dimen.staggered_damping_ratio);
|
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())
|
ValueAnimator springTransY = new SpringAnimationBuilder(v.getContext())
|
||||||
.setStiffness(stiffness)
|
.setStiffness(stiffness)
|
||||||
.setDampingRatio(damping)
|
.setDampingRatio(damping)
|
||||||
.setMinimumVisibleChange(1f)
|
.setMinimumVisibleChange(1f)
|
||||||
.setStartValue(mSpringTransY)
|
.setStartValue(mSpringTransY)
|
||||||
.setEndValue(0)
|
.setEndValue(endTransY)
|
||||||
.setStartVelocity(mVelocity)
|
.setStartVelocity(springVelocity)
|
||||||
.build(v, VIEW_TRANSLATE_Y);
|
.build(v, VIEW_TRANSLATE_Y);
|
||||||
springTransY.setStartDelay(startDelay);
|
springTransY.setStartDelay(startDelay);
|
||||||
springTransY.addListener(new AnimatorListenerAdapter() {
|
springTransY.addListener(new AnimatorListenerAdapter() {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.android.quickstep.util;
|
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.states.RotationHelper.deltaRotation;
|
||||||
import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
|
import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
|
||||||
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
|
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
|
||||||
|
@ -197,6 +198,15 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
|
||||||
return mTempRectF;
|
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() {
|
public RecentsOrientedState getOrientationState() {
|
||||||
return mOrientationState;
|
return mOrientationState;
|
||||||
}
|
}
|
||||||
|
@ -295,6 +305,10 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
|
||||||
builder.withMatrix(mMatrix)
|
builder.withMatrix(mMatrix)
|
||||||
.withWindowCrop(mTmpCropRect)
|
.withWindowCrop(mTmpCropRect)
|
||||||
.withCornerRadius(getCurrentCornerRadius());
|
.withCornerRadius(getCurrentCornerRadius());
|
||||||
|
|
||||||
|
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.getRecentsSurface() != null) {
|
||||||
|
builder.withRelativeLayerTo(params.getRecentsSurface(), Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package com.android.quickstep.util;
|
package com.android.quickstep.util;
|
||||||
|
|
||||||
import android.util.FloatProperty;
|
import android.util.FloatProperty;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.anim.Interpolators;
|
import com.android.launcher3.anim.Interpolators;
|
||||||
|
@ -58,6 +59,7 @@ public class TransformParams {
|
||||||
private float mCornerRadius;
|
private float mCornerRadius;
|
||||||
private RemoteAnimationTargets mTargetSet;
|
private RemoteAnimationTargets mTargetSet;
|
||||||
private SurfaceTransactionApplier mSyncTransactionApplier;
|
private SurfaceTransactionApplier mSyncTransactionApplier;
|
||||||
|
private SurfaceControl mRecentsSurface;
|
||||||
|
|
||||||
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
|
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
|
||||||
private BuilderProxy mBaseBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
|
private BuilderProxy mBaseBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
|
||||||
|
@ -138,6 +140,8 @@ public class TransformParams {
|
||||||
public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
|
public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
|
||||||
RemoteAnimationTargets targets = mTargetSet;
|
RemoteAnimationTargets targets = mTargetSet;
|
||||||
SurfaceParams[] surfaceParams = new SurfaceParams[targets.unfilteredApps.length];
|
SurfaceParams[] surfaceParams = new SurfaceParams[targets.unfilteredApps.length];
|
||||||
|
mRecentsSurface = getRecentsSurface(targets);
|
||||||
|
|
||||||
for (int i = 0; i < targets.unfilteredApps.length; i++) {
|
for (int i = 0; i < targets.unfilteredApps.length; i++) {
|
||||||
RemoteAnimationTargetCompat app = targets.unfilteredApps[i];
|
RemoteAnimationTargetCompat app = targets.unfilteredApps[i];
|
||||||
SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
|
SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
|
||||||
|
@ -165,6 +169,20 @@ public class TransformParams {
|
||||||
return surfaceParams;
|
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.
|
// Pubic getters so outside packages can read the values.
|
||||||
|
|
||||||
public float getProgress() {
|
public float getProgress() {
|
||||||
|
@ -179,6 +197,10 @@ public class TransformParams {
|
||||||
return mCornerRadius;
|
return mCornerRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SurfaceControl getRecentsSurface() {
|
||||||
|
return mRecentsSurface;
|
||||||
|
}
|
||||||
|
|
||||||
public RemoteAnimationTargets getTargetSet() {
|
public RemoteAnimationTargets getTargetSet() {
|
||||||
return mTargetSet;
|
return mTargetSet;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package com.android.quickstep.views;
|
package com.android.quickstep.views;
|
||||||
|
|
||||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
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.ACCEL;
|
||||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||||
|
@ -42,8 +43,10 @@ import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.Launcher;
|
import com.android.launcher3.Launcher;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
|
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
import com.android.launcher3.anim.Interpolators;
|
import com.android.launcher3.anim.Interpolators;
|
||||||
|
import com.android.launcher3.anim.PendingAnimation;
|
||||||
import com.android.launcher3.dragndrop.DragLayer;
|
import com.android.launcher3.dragndrop.DragLayer;
|
||||||
import com.android.launcher3.states.StateAnimationConfig;
|
import com.android.launcher3.states.StateAnimationConfig;
|
||||||
import com.android.launcher3.util.Themes;
|
import com.android.launcher3.util.Themes;
|
||||||
|
@ -51,6 +54,7 @@ import com.android.quickstep.util.MultiValueUpdateListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View used to educate the user on how to access All Apps when in No Nav Button navigation mode.
|
* View used to educate the user on how to access All Apps when in No Nav Button navigation mode.
|
||||||
|
* Consumes all touches until after the animation is completed and the view is removed.
|
||||||
*/
|
*/
|
||||||
public class AllAppsEduView extends AbstractFloatingView {
|
public class AllAppsEduView extends AbstractFloatingView {
|
||||||
|
|
||||||
|
@ -110,9 +114,19 @@ public class AllAppsEduView extends AbstractFloatingView {
|
||||||
return (type & TYPE_ALL_APPS_EDU) != 0;
|
return (type & TYPE_ALL_APPS_EDU) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onBackPressed() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canInterceptEventsInSystemGestureRegion() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
||||||
return mAnimation != null && mAnimation.isRunning();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void playAnimation() {
|
private void playAnimation() {
|
||||||
|
@ -139,7 +153,12 @@ public class AllAppsEduView extends AbstractFloatingView {
|
||||||
config.userControlled = false;
|
config.userControlled = false;
|
||||||
AnimatorPlaybackController stateAnimationController =
|
AnimatorPlaybackController stateAnimationController =
|
||||||
mLauncher.getStateManager().createAnimationToNewWorkspace(ALL_APPS, config);
|
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);
|
ValueAnimator intro = ValueAnimator.ofFloat(0, 1f);
|
||||||
intro.setInterpolator(LINEAR);
|
intro.setInterpolator(LINEAR);
|
||||||
|
@ -191,7 +210,8 @@ public class AllAppsEduView extends AbstractFloatingView {
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationEnd(Animator animation) {
|
public void onAnimationEnd(Animator animation) {
|
||||||
mAnimation = null;
|
mAnimation = null;
|
||||||
stateAnimationController.dispatchOnCancel();
|
// Handles cancelling the animation used to hint towards All Apps.
|
||||||
|
mLauncher.getStateManager().goToState(NORMAL, false);
|
||||||
handleClose(false);
|
handleClose(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,7 +31,6 @@ import android.animation.ObjectAnimator;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.UserHandle;
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
@ -41,20 +40,15 @@ import com.android.launcher3.BaseQuickstepLauncher;
|
||||||
import com.android.launcher3.Hotseat;
|
import com.android.launcher3.Hotseat;
|
||||||
import com.android.launcher3.LauncherState;
|
import com.android.launcher3.LauncherState;
|
||||||
import com.android.launcher3.anim.Interpolators;
|
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.statehandlers.DepthController;
|
||||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||||
import com.android.launcher3.util.TraceHelper;
|
|
||||||
import com.android.launcher3.views.ScrimView;
|
import com.android.launcher3.views.ScrimView;
|
||||||
import com.android.quickstep.LauncherActivityInterface;
|
import com.android.quickstep.LauncherActivityInterface;
|
||||||
import com.android.quickstep.SysUINavigationMode;
|
import com.android.quickstep.SysUINavigationMode;
|
||||||
import com.android.quickstep.util.TransformParams;
|
import com.android.quickstep.util.TransformParams;
|
||||||
import com.android.systemui.plugins.PluginListener;
|
import com.android.systemui.plugins.PluginListener;
|
||||||
import com.android.systemui.plugins.RecentsExtraCard;
|
import com.android.systemui.plugins.RecentsExtraCard;
|
||||||
import com.android.systemui.shared.recents.model.Task;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link RecentsView} used in Launcher activity
|
* {@link RecentsView} used in Launcher activity
|
||||||
|
@ -180,18 +174,6 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
|
||||||
super.onTaskLaunchAnimationEnd(success);
|
super.onTaskLaunchAnimationEnd(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTaskLaunched(Task task) {
|
|
||||||
UserHandle user = UserHandle.of(task.key.userId);
|
|
||||||
AppLaunchTracker.INSTANCE.get(getContext()).onStartApp(task.getTopComponent(), user,
|
|
||||||
AppLaunchTracker.CONTAINER_OVERVIEW);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldUseMultiWindowTaskSizeStrategy() {
|
|
||||||
return TraceHelper.whitelistIpcs("isInMultiWindowMode", mActivity::isInMultiWindowMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrollTo(int x, int y) {
|
public void scrollTo(int x, int y) {
|
||||||
super.scrollTo(x, y);
|
super.scrollTo(x, y);
|
||||||
|
@ -237,9 +219,6 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
|
||||||
super.reset();
|
super.reset();
|
||||||
|
|
||||||
setLayoutRotation(Surface.ROTATION_0, Surface.ROTATION_0);
|
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
|
@Override
|
||||||
|
|
|
@ -70,12 +70,14 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||||
|
|
||||||
@IntDef(flag = true, value = {
|
@IntDef(flag = true, value = {
|
||||||
DISABLED_SCROLLING,
|
DISABLED_SCROLLING,
|
||||||
DISABLED_ROTATED})
|
DISABLED_ROTATED,
|
||||||
|
DISABLED_NO_THUMBNAIL})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface ActionsDisabledFlags { }
|
public @interface ActionsDisabledFlags { }
|
||||||
|
|
||||||
public static final int DISABLED_SCROLLING = 1 << 0;
|
public static final int DISABLED_SCROLLING = 1 << 0;
|
||||||
public static final int DISABLED_ROTATED = 1 << 1;
|
public static final int DISABLED_ROTATED = 1 << 1;
|
||||||
|
public static final int DISABLED_NO_THUMBNAIL = 1 << 2;
|
||||||
|
|
||||||
private static final int INDEX_CONTENT_ALPHA = 0;
|
private static final int INDEX_CONTENT_ALPHA = 0;
|
||||||
private static final int INDEX_VISIBILITY_ALPHA = 1;
|
private static final int INDEX_VISIBILITY_ALPHA = 1;
|
||||||
|
|
|
@ -55,10 +55,8 @@ import android.animation.LayoutTransition.TransitionListener;
|
||||||
import android.animation.ObjectAnimator;
|
import android.animation.ObjectAnimator;
|
||||||
import android.animation.ValueAnimator;
|
import android.animation.ValueAnimator;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
|
@ -135,6 +133,7 @@ import com.android.quickstep.util.TransformParams;
|
||||||
import com.android.systemui.plugins.ResourceProvider;
|
import com.android.systemui.plugins.ResourceProvider;
|
||||||
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
|
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
|
||||||
import com.android.systemui.shared.recents.model.Task;
|
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.recents.model.ThumbnailData;
|
||||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||||
import com.android.systemui.shared.system.LauncherEventUtil;
|
import com.android.systemui.shared.system.LauncherEventUtil;
|
||||||
|
@ -147,7 +146,7 @@ import java.util.function.Consumer;
|
||||||
/**
|
/**
|
||||||
* A list of recent tasks.
|
* 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
|
public abstract class RecentsView<T extends StatefulActivity> extends PagedView implements
|
||||||
Insettable, TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
|
Insettable, TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
|
||||||
InvariantDeviceProfile.OnIDPChangeListener, TaskVisualsChangeListener,
|
InvariantDeviceProfile.OnIDPChangeListener, TaskVisualsChangeListener,
|
||||||
|
@ -377,7 +376,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||||
mOrientationState.setMultiWindowMode(inMultiWindowMode);
|
mOrientationState.setMultiWindowMode(inMultiWindowMode);
|
||||||
setLayoutRotation(mOrientationState.getTouchRotation(),
|
setLayoutRotation(mOrientationState.getTouchRotation(),
|
||||||
mOrientationState.getDisplayRotation());
|
mOrientationState.getDisplayRotation());
|
||||||
rotateAllChildTasks();
|
updateChildTaskOrientations();
|
||||||
}
|
}
|
||||||
if (!inMultiWindowMode && mOverviewStateEnabled) {
|
if (!inMultiWindowMode && mOverviewStateEnabled) {
|
||||||
// TODO: Re-enable layout transitions for addition of the unpinned task
|
// TODO: Re-enable layout transitions for addition of the unpinned task
|
||||||
|
@ -1041,13 +1040,13 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||||
/**
|
/**
|
||||||
* Called when a gesture from an app is starting.
|
* 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
|
// This needs to be called before the other states are set since it can create the task view
|
||||||
if (mOrientationState.setGestureActive(true)) {
|
if (mOrientationState.setGestureActive(true)) {
|
||||||
updateOrientationHandler();
|
updateOrientationHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
showCurrentTask(runningTaskId);
|
showCurrentTask(runningTaskInfo);
|
||||||
setEnableFreeScroll(false);
|
setEnableFreeScroll(false);
|
||||||
setEnableDrawingLiveTile(false);
|
setEnableDrawingLiveTile(false);
|
||||||
setRunningTaskHidden(true);
|
setRunningTaskHidden(true);
|
||||||
|
@ -1078,7 +1077,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||||
pa.addListener(AnimationSuccessListener.forRunnable(() -> {
|
pa.addListener(AnimationSuccessListener.forRunnable(() -> {
|
||||||
setLayoutRotation(newRotation, mOrientationState.getDisplayRotation());
|
setLayoutRotation(newRotation, mOrientationState.getDisplayRotation());
|
||||||
mActivity.getDragLayer().recreateControllers();
|
mActivity.getDragLayer().recreateControllers();
|
||||||
rotateAllChildTasks();
|
updateChildTaskOrientations();
|
||||||
setRecentsChangedOrientation(false).start();
|
setRecentsChangedOrientation(false).start();
|
||||||
}));
|
}));
|
||||||
pa.start();
|
pa.start();
|
||||||
|
@ -1099,7 +1098,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void rotateAllChildTasks() {
|
private void updateChildTaskOrientations() {
|
||||||
for (int i = 0; i < getTaskViewCount(); i++) {
|
for (int i = 0; i < getTaskViewCount(); i++) {
|
||||||
getTaskViewAt(i).setOrientationState(mOrientationState);
|
getTaskViewAt(i).setOrientationState(mOrientationState);
|
||||||
}
|
}
|
||||||
|
@ -1127,8 +1126,8 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||||
/**
|
/**
|
||||||
* Returns true if we should add a dummy taskView for the running task id
|
* Returns true if we should add a dummy taskView for the running task id
|
||||||
*/
|
*/
|
||||||
protected boolean shouldAddDummyTaskView(int runningTaskId) {
|
protected boolean shouldAddDummyTaskView(RunningTaskInfo runningTaskInfo) {
|
||||||
return getTaskView(runningTaskId) == null;
|
return runningTaskInfo != null && getTaskView(runningTaskInfo.taskId) == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1137,8 +1136,8 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||||
* All subsequent calls to reload will keep the task as the first item until {@link #reset()}
|
* 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.
|
* is called. Also scrolls the view to this task.
|
||||||
*/
|
*/
|
||||||
public void showCurrentTask(int runningTaskId) {
|
public void showCurrentTask(RunningTaskInfo runningTaskInfo) {
|
||||||
if (shouldAddDummyTaskView(runningTaskId)) {
|
if (shouldAddDummyTaskView(runningTaskInfo)) {
|
||||||
boolean wasEmpty = getChildCount() == 0;
|
boolean wasEmpty = getChildCount() == 0;
|
||||||
// Add an empty view for now until the task plan is loaded and applied
|
// Add an empty view for now until the task plan is loaded and applied
|
||||||
final TaskView taskView = mTaskViewPool.getView();
|
final TaskView taskView = mTaskViewPool.getView();
|
||||||
|
@ -1148,10 +1147,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||||
}
|
}
|
||||||
// The temporary running task is only used for the duration between the start of the
|
// The temporary running task is only used for the duration between the start of the
|
||||||
// gesture and the task list is loaded and applied
|
// gesture and the task list is loaded and applied
|
||||||
mTmpRunningTask = new Task(new Task.TaskKey(runningTaskId, 0, new Intent(),
|
mTmpRunningTask = Task.from(new TaskKey(runningTaskInfo), runningTaskInfo, false);
|
||||||
new ComponentName(getContext(), getClass()), 0, 0), null, null, "", "", 0, 0,
|
|
||||||
false, true, false, false, new ActivityManager.TaskDescription(), 0,
|
|
||||||
new ComponentName("", ""), false);
|
|
||||||
taskView.bind(mTmpRunningTask, mOrientationState);
|
taskView.bind(mTmpRunningTask, mOrientationState);
|
||||||
|
|
||||||
// Measure and layout immediately so that the scroll values is updated instantly
|
// Measure and layout immediately so that the scroll values is updated instantly
|
||||||
|
@ -1162,7 +1158,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean runningTaskTileHidden = mRunningTaskTileHidden;
|
boolean runningTaskTileHidden = mRunningTaskTileHidden;
|
||||||
setCurrentTask(runningTaskId);
|
setCurrentTask(runningTaskInfo == null ? -1 : runningTaskInfo.taskId);
|
||||||
setCurrentPage(getRunningTaskIndex());
|
setCurrentPage(getRunningTaskIndex());
|
||||||
setRunningTaskViewShowScreenshot(false);
|
setRunningTaskViewShowScreenshot(false);
|
||||||
setRunningTaskHidden(runningTaskTileHidden);
|
setRunningTaskHidden(runningTaskTileHidden);
|
||||||
|
@ -1652,6 +1648,9 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||||
super.setVisibility(visibility);
|
super.setVisibility(visibility);
|
||||||
if (mActionsView != null) {
|
if (mActionsView != null) {
|
||||||
mActionsView.updateHiddenFlags(HIDDEN_NO_RECENTS, visibility != VISIBLE);
|
mActionsView.updateHiddenFlags(HIDDEN_NO_RECENTS, visibility != VISIBLE);
|
||||||
|
if (visibility != VISIBLE) {
|
||||||
|
mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1680,10 +1679,11 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||||
: View.LAYOUT_DIRECTION_RTL);
|
: View.LAYOUT_DIRECTION_RTL);
|
||||||
mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
|
mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
|
||||||
mActivity.getDragLayer().recreateControllers();
|
mActivity.getDragLayer().recreateControllers();
|
||||||
boolean isInLandscape = mOrientationState.getTouchRotation() != 0
|
boolean isInLandscape = mOrientationState.getTouchRotation() != ROTATION_0
|
||||||
|| mOrientationState.getRecentsActivityRotation() != ROTATION_0;
|
|| mOrientationState.getRecentsActivityRotation() != ROTATION_0;
|
||||||
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
|
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
|
||||||
!mOrientationState.canRecentsActivityRotate() && isInLandscape);
|
!mOrientationState.canRecentsActivityRotate() && isInLandscape);
|
||||||
|
updateChildTaskOrientations();
|
||||||
resetPaddingFromTaskSize();
|
resetPaddingFromTaskSize();
|
||||||
requestLayout();
|
requestLayout();
|
||||||
// Reapply the current page to update page scrolls.
|
// Reapply the current page to update page scrolls.
|
||||||
|
@ -1998,19 +1998,12 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
|
||||||
protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) {
|
protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract boolean shouldUseMultiWindowTaskSizeStrategy();
|
|
||||||
|
|
||||||
protected void onTaskLaunchAnimationEnd(boolean success) {
|
protected void onTaskLaunchAnimationEnd(boolean success) {
|
||||||
if (success) {
|
if (success) {
|
||||||
resetTaskVisuals();
|
resetTaskVisuals();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when task activity is launched
|
|
||||||
*/
|
|
||||||
public void onTaskLaunched(Task task){ }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notifyPageSwitchListener(int prevPage) {
|
protected void notifyPageSwitchListener(int prevPage) {
|
||||||
super.notifyPageSwitchListener(prevPage);
|
super.notifyPageSwitchListener(prevPage);
|
||||||
|
|
|
@ -169,7 +169,9 @@ public class TaskMenuView extends AbstractFloatingView {
|
||||||
}
|
}
|
||||||
if (mIsOpen) {
|
if (mIsOpen) {
|
||||||
mOptionLayout.removeAllViews();
|
mOptionLayout.removeAllViews();
|
||||||
populateAndLayoutMenu();
|
if (!populateAndLayoutMenu()) {
|
||||||
|
close(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,14 +188,22 @@ public class TaskMenuView extends AbstractFloatingView {
|
||||||
}
|
}
|
||||||
mActivity.getDragLayer().addView(this);
|
mActivity.getDragLayer().addView(this);
|
||||||
mTaskView = taskView;
|
mTaskView = taskView;
|
||||||
populateAndLayoutMenu();
|
if (!populateAndLayoutMenu()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
post(this::animateOpen);
|
post(this::animateOpen);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateAndLayoutMenu() {
|
/** @return true if successfully able to populate task view menu, false otherwise */
|
||||||
|
private boolean populateAndLayoutMenu() {
|
||||||
|
if (mTaskView.getTask().icon == null) {
|
||||||
|
// Icon may not be loaded
|
||||||
|
return false;
|
||||||
|
}
|
||||||
addMenuOptions(mTaskView);
|
addMenuOptions(mTaskView);
|
||||||
orientAroundTaskView(mTaskView);
|
orientAroundTaskView(mTaskView);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMenuOptions(TaskView taskView) {
|
private void addMenuOptions(TaskView taskView) {
|
||||||
|
@ -240,8 +250,10 @@ public class TaskMenuView extends AbstractFloatingView {
|
||||||
setLayoutParams(params);
|
setLayoutParams(params);
|
||||||
setScaleX(taskView.getScaleX());
|
setScaleX(taskView.getScaleX());
|
||||||
setScaleY(taskView.getScaleY());
|
setScaleY(taskView.getScaleY());
|
||||||
|
boolean canActivityRotate = taskView.getRecentsView()
|
||||||
|
.mOrientationState.canRecentsActivityRotate();
|
||||||
mOptionLayout.setOrientation(orientationHandler
|
mOptionLayout.setOrientation(orientationHandler
|
||||||
.getTaskMenuLayoutOrientation(mOptionLayout));
|
.getTaskMenuLayoutOrientation(canActivityRotate, mOptionLayout));
|
||||||
setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top,
|
setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top,
|
||||||
taskView.getPagedOrientationHandler());
|
taskView.getPagedOrientationHandler());
|
||||||
}
|
}
|
||||||
|
|
|
@ -357,7 +357,7 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOverlay() {
|
private void updateOverlay() {
|
||||||
if (mOverlayEnabled && mBitmapShader != null && mThumbnailData != null) {
|
if (mOverlayEnabled) {
|
||||||
mOverlay.initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
|
mOverlay.initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
|
||||||
mPreviewPositionHelper.mIsOrientationChanged);
|
mPreviewPositionHelper.mIsOrientationChanged);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -30,8 +30,7 @@ import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||||
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
||||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
|
||||||
.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
|
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
|
@ -385,7 +384,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||||
}
|
}
|
||||||
}, resultCallbackHandler);
|
}, resultCallbackHandler);
|
||||||
}
|
}
|
||||||
getRecentsView().onTaskLaunched(mTask);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2020 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="#FFFFFFFF" />
|
||||||
|
</shape>
|
|
@ -24,6 +24,14 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@drawable/gesture_tutorial_ripple"/>
|
android:background="@drawable/gesture_tutorial_ripple"/>
|
||||||
|
|
||||||
|
<com.android.launcher3.views.ClipIconView
|
||||||
|
android:id="@+id/gesture_tutorial_fake_icon_view"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:background="@drawable/bg_circle"
|
||||||
|
android:backgroundTint="@color/gesture_tutorial_fake_task_view_color"
|
||||||
|
android:visibility="invisible" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/gesture_tutorial_fake_task_view"
|
android:id="@+id/gesture_tutorial_fake_task_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -41,81 +49,81 @@
|
||||||
android:id="@+id/gesture_tutorial_fragment_close_button"
|
android:id="@+id/gesture_tutorial_fragment_close_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="18dp"
|
|
||||||
android:layout_marginTop="30dp"
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:background="@android:color/transparent"
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
android:accessibilityTraversalAfter="@id/gesture_tutorial_fragment_titles_container"
|
android:accessibilityTraversalAfter="@id/gesture_tutorial_fragment_titles_container"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
android:contentDescription="@string/gesture_tutorial_close_button_content_description"
|
android:contentDescription="@string/gesture_tutorial_close_button_content_description"
|
||||||
android:tint="?android:attr/textColorPrimary"
|
android:padding="18dp"
|
||||||
android:src="@drawable/gesture_tutorial_close_button"/>
|
android:src="@drawable/gesture_tutorial_close_button"
|
||||||
|
android:tint="?android:attr/textColorPrimary"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/gesture_tutorial_fragment_titles_container"
|
android:id="@+id/gesture_tutorial_fragment_titles_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="70dp"
|
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_marginTop="70dp"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/gesture_tutorial_fragment_title_view"
|
android:id="@+id/gesture_tutorial_fragment_title_view"
|
||||||
|
style="@style/TextAppearance.GestureTutorial.Title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/gesture_tutorial_title_margin_start_end"
|
android:layout_marginStart="@dimen/gesture_tutorial_title_margin_start_end"
|
||||||
android:layout_marginEnd="@dimen/gesture_tutorial_title_margin_start_end"
|
android:layout_marginEnd="@dimen/gesture_tutorial_title_margin_start_end"/>
|
||||||
style="@style/TextAppearance.GestureTutorial.Title"/>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/gesture_tutorial_fragment_subtitle_view"
|
android:id="@+id/gesture_tutorial_fragment_subtitle_view"
|
||||||
|
style="@style/TextAppearance.GestureTutorial.Subtitle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:layout_marginStart="@dimen/gesture_tutorial_subtitle_margin_start_end"
|
android:layout_marginStart="@dimen/gesture_tutorial_subtitle_margin_start_end"
|
||||||
android:layout_marginEnd="@dimen/gesture_tutorial_subtitle_margin_start_end"
|
android:layout_marginTop="10dp"
|
||||||
style="@style/TextAppearance.GestureTutorial.Subtitle"/>
|
android:layout_marginEnd="@dimen/gesture_tutorial_subtitle_margin_start_end"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/gesture_tutorial_fragment_feedback_view"
|
android:id="@+id/gesture_tutorial_fragment_feedback_view"
|
||||||
|
style="@style/TextAppearance.GestureTutorial.Feedback"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="10dp"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:layout_above="@id/gesture_tutorial_fragment_action_button"
|
android:layout_above="@id/gesture_tutorial_fragment_action_button"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
android:layout_marginStart="@dimen/gesture_tutorial_feedback_margin_start_end"
|
android:layout_marginStart="@dimen/gesture_tutorial_feedback_margin_start_end"
|
||||||
android:layout_marginEnd="@dimen/gesture_tutorial_feedback_margin_start_end"
|
android:layout_marginEnd="@dimen/gesture_tutorial_feedback_margin_start_end"
|
||||||
style="@style/TextAppearance.GestureTutorial.Feedback"/>
|
android:layout_marginBottom="10dp"/>
|
||||||
|
|
||||||
<!-- android:stateListAnimator="@null" removes shadow and normal on click behavior (increase
|
<!-- android:stateListAnimator="@null" removes shadow and normal on click behavior (increase
|
||||||
of elevation and shadow) which is replaced by ripple effect in android:foreground -->
|
of elevation and shadow) which is replaced by ripple effect in android:foreground -->
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/gesture_tutorial_fragment_action_button"
|
android:id="@+id/gesture_tutorial_fragment_action_button"
|
||||||
|
style="@style/TextAppearance.GestureTutorial.ButtonLabel"
|
||||||
android:layout_width="142dp"
|
android:layout_width="142dp"
|
||||||
android:layout_height="49dp"
|
android:layout_height="49dp"
|
||||||
android:layout_marginEnd="@dimen/gesture_tutorial_button_margin_start_end"
|
|
||||||
android:layout_marginBottom="48dp"
|
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:stateListAnimator="@null"
|
android:layout_marginEnd="@dimen/gesture_tutorial_button_margin_start_end"
|
||||||
|
android:layout_marginBottom="48dp"
|
||||||
android:background="@drawable/gesture_tutorial_action_button_background"
|
android:background="@drawable/gesture_tutorial_action_button_background"
|
||||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||||
style="@style/TextAppearance.GestureTutorial.ButtonLabel"/>
|
android:stateListAnimator="@null"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/gesture_tutorial_fragment_action_text_button"
|
android:id="@+id/gesture_tutorial_fragment_action_text_button"
|
||||||
|
style="@style/TextAppearance.GestureTutorial.TextButtonLabel"
|
||||||
android:layout_width="142dp"
|
android:layout_width="142dp"
|
||||||
android:layout_height="49dp"
|
android:layout_height="49dp"
|
||||||
android:layout_marginStart="@dimen/gesture_tutorial_button_margin_start_end"
|
|
||||||
android:layout_marginBottom="48dp"
|
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:stateListAnimator="@null"
|
android:layout_marginStart="@dimen/gesture_tutorial_button_margin_start_end"
|
||||||
|
android:layout_marginBottom="48dp"
|
||||||
android:background="@null"
|
android:background="@null"
|
||||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||||
style="@style/TextAppearance.GestureTutorial.TextButtonLabel"/>
|
android:stateListAnimator="@null"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
|
@ -17,6 +17,7 @@ package com.android.quickstep;
|
||||||
|
|
||||||
import static com.android.launcher3.util.LauncherUIHelper.doLayout;
|
import static com.android.launcher3.util.LauncherUIHelper.doLayout;
|
||||||
|
|
||||||
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Bitmap.Config;
|
import android.graphics.Bitmap.Config;
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ public class RecentsActivityTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecets_showCurrentTask() {
|
public void testRecents_showCurrentTask() {
|
||||||
ActivityController<RecentsActivity> controller =
|
ActivityController<RecentsActivity> controller =
|
||||||
Robolectric.buildActivity(RecentsActivity.class);
|
Robolectric.buildActivity(RecentsActivity.class);
|
||||||
|
|
||||||
|
@ -58,7 +59,10 @@ public class RecentsActivityTest {
|
||||||
doLayout(activity);
|
doLayout(activity);
|
||||||
|
|
||||||
FallbackRecentsView frv = activity.getOverviewPanel();
|
FallbackRecentsView frv = activity.getOverviewPanel();
|
||||||
frv.showCurrentTask(22);
|
|
||||||
|
RunningTaskInfo dummyTask = new RunningTaskInfo();
|
||||||
|
dummyTask.taskId = 22;
|
||||||
|
frv.showCurrentTask(dummyTask);
|
||||||
doLayout(activity);
|
doLayout(activity);
|
||||||
|
|
||||||
ThumbnailData thumbnailData = new ThumbnailData();
|
ThumbnailData thumbnailData = new ThumbnailData();
|
||||||
|
|
|
@ -157,6 +157,12 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||||
@Override
|
@Override
|
||||||
protected void onDeferredResumed() {
|
protected void onDeferredResumed() {
|
||||||
super.onDeferredResumed();
|
super.onDeferredResumed();
|
||||||
|
handlePendingActivityRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handlePendingActivityRequest() {
|
||||||
|
super.handlePendingActivityRequest();
|
||||||
if (mPendingActivityRequestCode != -1 && isInState(NORMAL)) {
|
if (mPendingActivityRequestCode != -1 && isInState(NORMAL)) {
|
||||||
// Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher.
|
// Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher.
|
||||||
onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null);
|
onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null);
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package com.android.launcher3;
|
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_ALL;
|
||||||
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
|
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
|
||||||
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
|
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
|
||||||
|
@ -62,7 +60,6 @@ import android.os.CancellationSignal;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.util.TypedValue;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
@ -879,10 +876,8 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
float velocityDpPerS = DynamicResource.provider(mLauncher)
|
float velocityPxPerS = DynamicResource.provider(mLauncher)
|
||||||
.getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
|
.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)
|
anim.play(new StaggeredWorkspaceAnim(mLauncher, velocityPxPerS, false)
|
||||||
.getAnimators());
|
.getAnimators());
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,16 +150,9 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
|
||||||
return deviceState.isInDeferredGestureRegion(ev);
|
return deviceState.isInDeferredGestureRegion(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void onExitOverview(RecentsAnimationDeviceState deviceState,
|
public abstract void onExitOverview(RotationTouchHelper deviceState,
|
||||||
Runnable exitRunnable);
|
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}
|
* Used for containerType in {@link com.android.launcher3.logging.UserEventDispatcher}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -16,11 +16,9 @@
|
||||||
package com.android.quickstep;
|
package com.android.quickstep;
|
||||||
|
|
||||||
import static android.content.Intent.ACTION_USER_UNLOCKED;
|
import static android.content.Intent.ACTION_USER_UNLOCKED;
|
||||||
import static android.view.Surface.ROTATION_0;
|
|
||||||
|
|
||||||
import static com.android.launcher3.util.DefaultDisplay.CHANGE_ALL;
|
import static com.android.launcher3.util.DefaultDisplay.CHANGE_ALL;
|
||||||
import static com.android.launcher3.util.DefaultDisplay.CHANGE_FRAME_DELAY;
|
import static com.android.launcher3.util.DefaultDisplay.CHANGE_FRAME_DELAY;
|
||||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
|
||||||
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
|
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
|
||||||
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
|
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
|
||||||
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
|
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
|
||||||
|
@ -49,23 +47,19 @@ import android.os.UserManager;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.OrientationEventListener;
|
|
||||||
|
|
||||||
import androidx.annotation.BinderThread;
|
import androidx.annotation.BinderThread;
|
||||||
|
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.testing.TestProtocol;
|
|
||||||
import com.android.launcher3.util.DefaultDisplay;
|
import com.android.launcher3.util.DefaultDisplay;
|
||||||
import com.android.launcher3.util.SecureSettingsObserver;
|
import com.android.launcher3.util.SecureSettingsObserver;
|
||||||
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
|
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
|
||||||
import com.android.quickstep.util.NavBarPosition;
|
import com.android.quickstep.util.NavBarPosition;
|
||||||
import com.android.quickstep.util.RecentsOrientedState;
|
|
||||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||||
import com.android.systemui.shared.system.QuickStepContract;
|
import com.android.systemui.shared.system.QuickStepContract;
|
||||||
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
|
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
|
||||||
import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
|
import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
|
||||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -83,7 +77,7 @@ public class RecentsAnimationDeviceState implements
|
||||||
private final SysUINavigationMode mSysUiNavMode;
|
private final SysUINavigationMode mSysUiNavMode;
|
||||||
private final DefaultDisplay mDefaultDisplay;
|
private final DefaultDisplay mDefaultDisplay;
|
||||||
private final int mDisplayId;
|
private final int mDisplayId;
|
||||||
private int mDisplayRotation;
|
private final RotationTouchHelper mRotationTouchHelper;
|
||||||
|
|
||||||
private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>();
|
private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -107,76 +101,10 @@ public class RecentsAnimationDeviceState implements
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private TaskStackChangeListener mFrozenTaskListener = new TaskStackChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onRecentTaskListFrozenChanged(boolean frozen) {
|
|
||||||
mTaskListFrozen = frozen;
|
|
||||||
if (frozen || mInOverview) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
enableMultipleRegions(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityRotation(int displayId) {
|
|
||||||
super.onActivityRotation(displayId);
|
|
||||||
// This always gets called before onDisplayInfoChanged() so we know how to process
|
|
||||||
// the rotation in that method. This is done to avoid having a race condition between
|
|
||||||
// the sensor readings and onDisplayInfoChanged() call
|
|
||||||
if (displayId != mDisplayId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mPrioritizeDeviceRotation = true;
|
|
||||||
if (mInOverview) {
|
|
||||||
// reset, launcher must be rotating
|
|
||||||
mExitOverviewRunnable.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private Runnable mExitOverviewRunnable = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mInOverview = false;
|
|
||||||
enableMultipleRegions(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private OrientationTouchTransformer mOrientationTouchTransformer;
|
|
||||||
/**
|
|
||||||
* Used to listen for when the device rotates into the orientation of the current
|
|
||||||
* foreground app. For example, if a user quickswitches from a portrait to a fixed landscape
|
|
||||||
* app and then rotates rotates the device to match that orientation, this triggers calls to
|
|
||||||
* sysui to adjust the navbar.
|
|
||||||
*/
|
|
||||||
private OrientationEventListener mOrientationListener;
|
|
||||||
private int mSensorRotation = ROTATION_0;
|
|
||||||
/**
|
|
||||||
* This is the configuration of the foreground app or the app that will be in the foreground
|
|
||||||
* once a quickstep gesture finishes.
|
|
||||||
*/
|
|
||||||
private int mCurrentAppRotation = -1;
|
|
||||||
/**
|
|
||||||
* This flag is set to true when the device physically changes orientations. When true,
|
|
||||||
* we will always report the current rotation of the foreground app whenever the display
|
|
||||||
* changes, as it would indicate the user's intention to rotate the foreground app.
|
|
||||||
*/
|
|
||||||
private boolean mPrioritizeDeviceRotation = false;
|
|
||||||
|
|
||||||
private Region mExclusionRegion;
|
private Region mExclusionRegion;
|
||||||
private SystemGestureExclusionListenerCompat mExclusionListener;
|
private SystemGestureExclusionListenerCompat mExclusionListener;
|
||||||
|
|
||||||
private final List<ComponentName> mGestureBlockedActivities;
|
private final List<ComponentName> mGestureBlockedActivities;
|
||||||
private Runnable mOnDestroyFrozenTaskRunnable;
|
|
||||||
/**
|
|
||||||
* Set to true when user swipes to recents. In recents, we ignore the state of the recents
|
|
||||||
* task list being frozen or not to allow the user to keep interacting with nav bar rotation
|
|
||||||
* they went into recents with as opposed to defaulting to the default display rotation.
|
|
||||||
* TODO: (b/156984037) For when user rotates after entering overview
|
|
||||||
*/
|
|
||||||
private boolean mInOverview;
|
|
||||||
private boolean mTaskListFrozen;
|
|
||||||
|
|
||||||
private boolean mIsUserSetupComplete;
|
private boolean mIsUserSetupComplete;
|
||||||
|
|
||||||
|
@ -186,6 +114,8 @@ public class RecentsAnimationDeviceState implements
|
||||||
mDefaultDisplay = DefaultDisplay.INSTANCE.get(context);
|
mDefaultDisplay = DefaultDisplay.INSTANCE.get(context);
|
||||||
mDisplayId = mDefaultDisplay.getInfo().id;
|
mDisplayId = mDefaultDisplay.getInfo().id;
|
||||||
runOnDestroy(() -> mDefaultDisplay.removeChangeListener(this));
|
runOnDestroy(() -> mDefaultDisplay.removeChangeListener(this));
|
||||||
|
mRotationTouchHelper = RotationTouchHelper.INSTANCE.get(context);
|
||||||
|
runOnDestroy(mRotationTouchHelper::destroy);
|
||||||
|
|
||||||
// Register for user unlocked if necessary
|
// Register for user unlocked if necessary
|
||||||
mIsUserUnlocked = context.getSystemService(UserManager.class)
|
mIsUserUnlocked = context.getSystemService(UserManager.class)
|
||||||
|
@ -207,10 +137,6 @@ public class RecentsAnimationDeviceState implements
|
||||||
};
|
};
|
||||||
runOnDestroy(mExclusionListener::unregister);
|
runOnDestroy(mExclusionListener::unregister);
|
||||||
|
|
||||||
Resources resources = mContext.getResources();
|
|
||||||
mOrientationTouchTransformer = new OrientationTouchTransformer(resources, mMode,
|
|
||||||
() -> QuickStepContract.getWindowCornerRadius(resources));
|
|
||||||
|
|
||||||
// Register for navigation mode changes
|
// Register for navigation mode changes
|
||||||
onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this));
|
onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this));
|
||||||
runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(this));
|
runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(this));
|
||||||
|
@ -241,38 +167,6 @@ public class RecentsAnimationDeviceState implements
|
||||||
userSetupObserver.register();
|
userSetupObserver.register();
|
||||||
runOnDestroy(userSetupObserver::unregister);
|
runOnDestroy(userSetupObserver::unregister);
|
||||||
}
|
}
|
||||||
|
|
||||||
mOrientationListener = new OrientationEventListener(context) {
|
|
||||||
@Override
|
|
||||||
public void onOrientationChanged(int degrees) {
|
|
||||||
int newRotation = RecentsOrientedState.getRotationForUserDegreesRotated(degrees,
|
|
||||||
mSensorRotation);
|
|
||||||
if (newRotation == mSensorRotation) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mSensorRotation = newRotation;
|
|
||||||
mPrioritizeDeviceRotation = true;
|
|
||||||
|
|
||||||
if (newRotation == mCurrentAppRotation) {
|
|
||||||
// When user rotates device to the orientation of the foreground app after
|
|
||||||
// quickstepping
|
|
||||||
toggleSecondaryNavBarsForRotation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupOrientationSwipeHandler() {
|
|
||||||
ActivityManagerWrapper.getInstance().registerTaskStackListener(mFrozenTaskListener);
|
|
||||||
mOnDestroyFrozenTaskRunnable = () -> ActivityManagerWrapper.getInstance()
|
|
||||||
.unregisterTaskStackListener(mFrozenTaskListener);
|
|
||||||
runOnDestroy(mOnDestroyFrozenTaskRunnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void destroyOrientationSwipeHandlerCallback() {
|
|
||||||
ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mFrozenTaskListener);
|
|
||||||
mOnDestroyActions.remove(mOnDestroyFrozenTaskRunnable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runOnDestroy(Runnable action) {
|
private void runOnDestroy(Runnable action) {
|
||||||
|
@ -311,13 +205,6 @@ public class RecentsAnimationDeviceState implements
|
||||||
|
|
||||||
mNavBarPosition = new NavBarPosition(newMode, mDefaultDisplay.getInfo());
|
mNavBarPosition = new NavBarPosition(newMode, mDefaultDisplay.getInfo());
|
||||||
|
|
||||||
mOrientationTouchTransformer.setNavigationMode(newMode, mDefaultDisplay.getInfo());
|
|
||||||
if (!mMode.hasGestures && newMode.hasGestures) {
|
|
||||||
setupOrientationSwipeHandler();
|
|
||||||
} else if (mMode.hasGestures && !newMode.hasGestures){
|
|
||||||
destroyOrientationSwipeHandlerCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
mMode = newMode;
|
mMode = newMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,28 +215,10 @@ public class RecentsAnimationDeviceState implements
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mDisplayRotation = info.rotation;
|
|
||||||
|
|
||||||
if (!mMode.hasGestures) {
|
if (!mMode.hasGestures) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mNavBarPosition = new NavBarPosition(mMode, info);
|
mNavBarPosition = new NavBarPosition(mMode, info);
|
||||||
updateGestureTouchRegions();
|
|
||||||
mOrientationTouchTransformer.createOrAddTouchRegion(info);
|
|
||||||
mCurrentAppRotation = mDisplayRotation;
|
|
||||||
|
|
||||||
/* Update nav bars on the following:
|
|
||||||
* a) if this is coming from an activity rotation OR
|
|
||||||
* aa) we launch an app in the orientation that user is already in
|
|
||||||
* b) We're not in overview, since overview will always be portrait (w/o home rotation)
|
|
||||||
* c) We're actively in quickswitch mode
|
|
||||||
*/
|
|
||||||
if ((mPrioritizeDeviceRotation
|
|
||||||
|| mCurrentAppRotation == mSensorRotation) // switch to an app of orientation user is in
|
|
||||||
&& !mInOverview
|
|
||||||
&& mTaskListFrozen) {
|
|
||||||
toggleSecondaryNavBarsForRotation();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -464,7 +333,7 @@ public class RecentsAnimationDeviceState implements
|
||||||
*/
|
*/
|
||||||
public boolean canStartSystemGesture() {
|
public boolean canStartSystemGesture() {
|
||||||
boolean canStartWithNavHidden = (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
|
boolean canStartWithNavHidden = (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
|
||||||
|| mTaskListFrozen;
|
|| mRotationTouchHelper.isTaskListFrozen();
|
||||||
return canStartWithNavHidden
|
return canStartWithNavHidden
|
||||||
&& (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
|
&& (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
|
||||||
&& (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0
|
&& (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0
|
||||||
|
@ -536,33 +405,6 @@ public class RecentsAnimationDeviceState implements
|
||||||
return (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0;
|
return (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the regions for detecting the swipe up/quickswitch and assistant gestures.
|
|
||||||
*/
|
|
||||||
public void updateGestureTouchRegions() {
|
|
||||||
if (!mMode.hasGestures) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mOrientationTouchTransformer.createOrAddTouchRegion(mDefaultDisplay.getInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return whether the coordinates of the {@param event} is in the swipe up gesture region.
|
|
||||||
*/
|
|
||||||
public boolean isInSwipeUpTouchRegion(MotionEvent event) {
|
|
||||||
return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(), event.getY());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return whether the coordinates of the {@param event} with the given {@param pointerIndex}
|
|
||||||
* is in the swipe up gesture region.
|
|
||||||
*/
|
|
||||||
public boolean isInSwipeUpTouchRegion(MotionEvent event, int pointerIndex) {
|
|
||||||
return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(pointerIndex),
|
|
||||||
event.getY(pointerIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the region in screen space where the gestures should be deferred (ie. due to specific
|
* Sets the region in screen space where the gestures should be deferred (ie. due to specific
|
||||||
* nav bar ui).
|
* nav bar ui).
|
||||||
|
@ -620,101 +462,13 @@ public class RecentsAnimationDeviceState implements
|
||||||
public boolean canTriggerAssistantAction(MotionEvent ev, ActivityManager.RunningTaskInfo task) {
|
public boolean canTriggerAssistantAction(MotionEvent ev, ActivityManager.RunningTaskInfo task) {
|
||||||
return mAssistantAvailable
|
return mAssistantAvailable
|
||||||
&& !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
|
&& !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
|
||||||
&& mOrientationTouchTransformer.touchInAssistantRegion(ev)
|
&& mRotationTouchHelper.touchInAssistantRegion(ev)
|
||||||
&& !isLockToAppActive()
|
&& !isLockToAppActive()
|
||||||
&& !isGestureBlockedActivity(task);
|
&& !isGestureBlockedActivity(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public RotationTouchHelper getRotationTouchHelper() {
|
||||||
* *May* apply a transform on the motion event if it lies in the nav bar region for another
|
return mRotationTouchHelper;
|
||||||
* orientation that is currently being tracked as a part of quickstep
|
|
||||||
*/
|
|
||||||
void setOrientationTransformIfNeeded(MotionEvent event) {
|
|
||||||
// negative coordinates bug b/143901881
|
|
||||||
if (event.getX() < 0 || event.getY() < 0) {
|
|
||||||
event.setLocation(Math.max(0, event.getX()), Math.max(0, event.getY()));
|
|
||||||
}
|
|
||||||
mOrientationTouchTransformer.transform(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enableMultipleRegions(boolean enable) {
|
|
||||||
mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
|
|
||||||
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getQuickStepStartingRotation());
|
|
||||||
if (enable && !mInOverview && !TestProtocol.sDisableSensorRotation) {
|
|
||||||
// Clear any previous state from sensor manager
|
|
||||||
mSensorRotation = mCurrentAppRotation;
|
|
||||||
mOrientationListener.enable();
|
|
||||||
} else {
|
|
||||||
mOrientationListener.disable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onStartGesture() {
|
|
||||||
if (mTaskListFrozen) {
|
|
||||||
// Prioritize whatever nav bar user touches once in quickstep
|
|
||||||
// This case is specifically when user changes what nav bar they are using mid
|
|
||||||
// quickswitch session before tasks list is unfrozen
|
|
||||||
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onEndTargetCalculated(GestureState.GestureEndTarget endTarget,
|
|
||||||
BaseActivityInterface activityInterface) {
|
|
||||||
if (endTarget == GestureState.GestureEndTarget.RECENTS) {
|
|
||||||
mInOverview = true;
|
|
||||||
if (!mTaskListFrozen) {
|
|
||||||
// If we're in landscape w/o ever quickswitching, show the navbar in landscape
|
|
||||||
enableMultipleRegions(true);
|
|
||||||
}
|
|
||||||
activityInterface.onExitOverview(this, mExitOverviewRunnable);
|
|
||||||
} else if (endTarget == GestureState.GestureEndTarget.HOME) {
|
|
||||||
enableMultipleRegions(false);
|
|
||||||
} else if (endTarget == GestureState.GestureEndTarget.NEW_TASK) {
|
|
||||||
if (mOrientationTouchTransformer.getQuickStepStartingRotation() == -1) {
|
|
||||||
// First gesture to start quickswitch
|
|
||||||
enableMultipleRegions(true);
|
|
||||||
} else {
|
|
||||||
notifySysuiOfCurrentRotation(
|
|
||||||
mOrientationTouchTransformer.getCurrentActiveRotation());
|
|
||||||
}
|
|
||||||
|
|
||||||
// A new gesture is starting, reset the current device rotation
|
|
||||||
// This is done under the assumption that the user won't rotate the phone and then
|
|
||||||
// quickswitch in the old orientation.
|
|
||||||
mPrioritizeDeviceRotation = false;
|
|
||||||
} else if (endTarget == GestureState.GestureEndTarget.LAST_TASK) {
|
|
||||||
if (!mTaskListFrozen) {
|
|
||||||
// touched nav bar but didn't go anywhere and not quickswitching, do nothing
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifySysuiOfCurrentRotation(int rotation) {
|
|
||||||
UI_HELPER_EXECUTOR.execute(() -> SystemUiProxy.INSTANCE.get(mContext)
|
|
||||||
.onQuickSwitchToNewTask(rotation));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables/Enables multiple nav bars on {@link OrientationTouchTransformer} and then
|
|
||||||
* notifies system UI of the primary rotation the user is interacting with
|
|
||||||
*/
|
|
||||||
private void toggleSecondaryNavBarsForRotation() {
|
|
||||||
mOrientationTouchTransformer.setSingleActiveRegion(mDefaultDisplay.getInfo());
|
|
||||||
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCurrentActiveRotation() {
|
|
||||||
if (!mMode.hasGestures) {
|
|
||||||
// touch rotation should always match that of display for 3 button
|
|
||||||
return mDisplayRotation;
|
|
||||||
}
|
|
||||||
return mOrientationTouchTransformer.getCurrentActiveRotation();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDisplayRotation() {
|
|
||||||
return mDisplayRotation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dump(PrintWriter pw) {
|
public void dump(PrintWriter pw) {
|
||||||
|
@ -726,9 +480,7 @@ public class RecentsAnimationDeviceState implements
|
||||||
pw.println(" assistantAvailable=" + mAssistantAvailable);
|
pw.println(" assistantAvailable=" + mAssistantAvailable);
|
||||||
pw.println(" assistantDisabled="
|
pw.println(" assistantDisabled="
|
||||||
+ QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
|
+ QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
|
||||||
pw.println(" currentActiveRotation=" + getCurrentActiveRotation());
|
|
||||||
pw.println(" displayRotation=" + getDisplayRotation());
|
|
||||||
pw.println(" isUserUnlocked=" + mIsUserUnlocked);
|
pw.println(" isUserUnlocked=" + mIsUserUnlocked);
|
||||||
mOrientationTouchTransformer.dump(pw);
|
mRotationTouchHelper.dump(pw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,15 +92,6 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||||
return mTaskList.getTasks(false /* loadKeysOnly */, callback);
|
return mTaskList.getTasks(false /* loadKeysOnly */, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @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.
|
* @return Whether the provided {@param changeId} is the latest recent tasks list id.
|
||||||
*/
|
*/
|
||||||
|
@ -140,7 +131,9 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep the cache up to date with the latest thumbnails
|
// 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 -> {
|
mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), tasks -> {
|
||||||
for (Task task : tasks) {
|
for (Task task : tasks) {
|
||||||
if (task.key.id == runningTaskId) {
|
if (task.key.id == runningTaskId) {
|
||||||
|
|
|
@ -0,0 +1,365 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.android.quickstep;
|
||||||
|
|
||||||
|
import static android.view.Surface.ROTATION_0;
|
||||||
|
|
||||||
|
import static com.android.launcher3.util.DefaultDisplay.CHANGE_ALL;
|
||||||
|
import static com.android.launcher3.util.DefaultDisplay.CHANGE_FRAME_DELAY;
|
||||||
|
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||||
|
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.OrientationEventListener;
|
||||||
|
|
||||||
|
import com.android.launcher3.testing.TestProtocol;
|
||||||
|
import com.android.launcher3.util.DefaultDisplay;
|
||||||
|
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||||
|
import com.android.quickstep.util.RecentsOrientedState;
|
||||||
|
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||||
|
import com.android.systemui.shared.system.QuickStepContract;
|
||||||
|
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class RotationTouchHelper implements
|
||||||
|
SysUINavigationMode.NavigationModeChangeListener,
|
||||||
|
DefaultDisplay.DisplayInfoChangeListener {
|
||||||
|
public static final MainThreadInitializedObject<RotationTouchHelper> INSTANCE =
|
||||||
|
new MainThreadInitializedObject<>(RotationTouchHelper::new);
|
||||||
|
|
||||||
|
private final OrientationTouchTransformer mOrientationTouchTransformer;
|
||||||
|
private final DefaultDisplay mDefaultDisplay;
|
||||||
|
private final SysUINavigationMode mSysUiNavMode;
|
||||||
|
private final int mDisplayId;
|
||||||
|
private int mDisplayRotation;
|
||||||
|
|
||||||
|
private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>();
|
||||||
|
|
||||||
|
private SysUINavigationMode.Mode mMode = THREE_BUTTONS;
|
||||||
|
|
||||||
|
private TaskStackChangeListener mFrozenTaskListener = new TaskStackChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onRecentTaskListFrozenChanged(boolean frozen) {
|
||||||
|
mTaskListFrozen = frozen;
|
||||||
|
if (frozen || mInOverview) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
enableMultipleRegions(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityRotation(int displayId) {
|
||||||
|
super.onActivityRotation(displayId);
|
||||||
|
// This always gets called before onDisplayInfoChanged() so we know how to process
|
||||||
|
// the rotation in that method. This is done to avoid having a race condition between
|
||||||
|
// the sensor readings and onDisplayInfoChanged() call
|
||||||
|
if (displayId != mDisplayId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPrioritizeDeviceRotation = true;
|
||||||
|
if (mInOverview) {
|
||||||
|
// reset, launcher must be rotating
|
||||||
|
mExitOverviewRunnable.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private Runnable mExitOverviewRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mInOverview = false;
|
||||||
|
enableMultipleRegions(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to listen for when the device rotates into the orientation of the current foreground
|
||||||
|
* app. For example, if a user quickswitches from a portrait to a fixed landscape app and then
|
||||||
|
* rotates rotates the device to match that orientation, this triggers calls to sysui to adjust
|
||||||
|
* the navbar.
|
||||||
|
*/
|
||||||
|
private OrientationEventListener mOrientationListener;
|
||||||
|
private int mSensorRotation = ROTATION_0;
|
||||||
|
/**
|
||||||
|
* This is the configuration of the foreground app or the app that will be in the foreground
|
||||||
|
* once a quickstep gesture finishes.
|
||||||
|
*/
|
||||||
|
private int mCurrentAppRotation = -1;
|
||||||
|
/**
|
||||||
|
* This flag is set to true when the device physically changes orientations. When true, we will
|
||||||
|
* always report the current rotation of the foreground app whenever the display changes, as it
|
||||||
|
* would indicate the user's intention to rotate the foreground app.
|
||||||
|
*/
|
||||||
|
private boolean mPrioritizeDeviceRotation = false;
|
||||||
|
private Runnable mOnDestroyFrozenTaskRunnable;
|
||||||
|
/**
|
||||||
|
* Set to true when user swipes to recents. In recents, we ignore the state of the recents
|
||||||
|
* task list being frozen or not to allow the user to keep interacting with nav bar rotation
|
||||||
|
* they went into recents with as opposed to defaulting to the default display rotation.
|
||||||
|
* TODO: (b/156984037) For when user rotates after entering overview
|
||||||
|
*/
|
||||||
|
private boolean mInOverview;
|
||||||
|
private boolean mTaskListFrozen;
|
||||||
|
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
|
private RotationTouchHelper(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
Resources resources = mContext.getResources();
|
||||||
|
mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context);
|
||||||
|
mDefaultDisplay = DefaultDisplay.INSTANCE.get(context);
|
||||||
|
mDisplayId = mDefaultDisplay.getInfo().id;
|
||||||
|
|
||||||
|
mOrientationTouchTransformer = new OrientationTouchTransformer(resources, mMode,
|
||||||
|
() -> QuickStepContract.getWindowCornerRadius(resources));
|
||||||
|
|
||||||
|
// Register for navigation mode changes
|
||||||
|
onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this));
|
||||||
|
runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(this));
|
||||||
|
|
||||||
|
mOrientationListener = new OrientationEventListener(context) {
|
||||||
|
@Override
|
||||||
|
public void onOrientationChanged(int degrees) {
|
||||||
|
int newRotation = RecentsOrientedState.getRotationForUserDegreesRotated(degrees,
|
||||||
|
mSensorRotation);
|
||||||
|
if (newRotation == mSensorRotation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSensorRotation = newRotation;
|
||||||
|
mPrioritizeDeviceRotation = true;
|
||||||
|
|
||||||
|
if (newRotation == mCurrentAppRotation) {
|
||||||
|
// When user rotates device to the orientation of the foreground app after
|
||||||
|
// quickstepping
|
||||||
|
toggleSecondaryNavBarsForRotation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupOrientationSwipeHandler() {
|
||||||
|
ActivityManagerWrapper.getInstance().registerTaskStackListener(mFrozenTaskListener);
|
||||||
|
mOnDestroyFrozenTaskRunnable = () -> ActivityManagerWrapper.getInstance()
|
||||||
|
.unregisterTaskStackListener(mFrozenTaskListener);
|
||||||
|
runOnDestroy(mOnDestroyFrozenTaskRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void destroyOrientationSwipeHandlerCallback() {
|
||||||
|
ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mFrozenTaskListener);
|
||||||
|
mOnDestroyActions.remove(mOnDestroyFrozenTaskRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runOnDestroy(Runnable action) {
|
||||||
|
mOnDestroyActions.add(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up all the registered listeners and receivers.
|
||||||
|
*/
|
||||||
|
public void destroy() {
|
||||||
|
for (Runnable r : mOnDestroyActions) {
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTaskListFrozen() {
|
||||||
|
return mTaskListFrozen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean touchInAssistantRegion(MotionEvent ev) {
|
||||||
|
return mOrientationTouchTransformer.touchInAssistantRegion(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the regions for detecting the swipe up/quickswitch and assistant gestures.
|
||||||
|
*/
|
||||||
|
public void updateGestureTouchRegions() {
|
||||||
|
if (!mMode.hasGestures) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mOrientationTouchTransformer.createOrAddTouchRegion(mDefaultDisplay.getInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return whether the coordinates of the {@param event} is in the swipe up gesture region.
|
||||||
|
*/
|
||||||
|
public boolean isInSwipeUpTouchRegion(MotionEvent event) {
|
||||||
|
return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(), event.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return whether the coordinates of the {@param event} with the given {@param pointerIndex}
|
||||||
|
* is in the swipe up gesture region.
|
||||||
|
*/
|
||||||
|
public boolean isInSwipeUpTouchRegion(MotionEvent event, int pointerIndex) {
|
||||||
|
return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(pointerIndex),
|
||||||
|
event.getY(pointerIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
|
||||||
|
mDefaultDisplay.removeChangeListener(this);
|
||||||
|
mDefaultDisplay.addChangeListener(this);
|
||||||
|
onDisplayInfoChanged(mDefaultDisplay.getInfo(), CHANGE_ALL);
|
||||||
|
|
||||||
|
mOrientationTouchTransformer.setNavigationMode(newMode, mDefaultDisplay.getInfo());
|
||||||
|
if (!mMode.hasGestures && newMode.hasGestures) {
|
||||||
|
setupOrientationSwipeHandler();
|
||||||
|
} else if (mMode.hasGestures && !newMode.hasGestures){
|
||||||
|
destroyOrientationSwipeHandlerCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
mMode = newMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDisplayRotation() {
|
||||||
|
return mDisplayRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) {
|
||||||
|
if (info.id != mDisplayId|| flags == CHANGE_FRAME_DELAY) {
|
||||||
|
// ignore displays that aren't running launcher and frame refresh rate changes
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDisplayRotation = info.rotation;
|
||||||
|
|
||||||
|
if (!mMode.hasGestures) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateGestureTouchRegions();
|
||||||
|
mOrientationTouchTransformer.createOrAddTouchRegion(info);
|
||||||
|
mCurrentAppRotation = mDisplayRotation;
|
||||||
|
|
||||||
|
/* Update nav bars on the following:
|
||||||
|
* a) if this is coming from an activity rotation OR
|
||||||
|
* aa) we launch an app in the orientation that user is already in
|
||||||
|
* b) We're not in overview, since overview will always be portrait (w/o home rotation)
|
||||||
|
* c) We're actively in quickswitch mode
|
||||||
|
*/
|
||||||
|
if ((mPrioritizeDeviceRotation
|
||||||
|
|| mCurrentAppRotation == mSensorRotation) // switch to an app of orientation user is in
|
||||||
|
&& !mInOverview
|
||||||
|
&& mTaskListFrozen) {
|
||||||
|
toggleSecondaryNavBarsForRotation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* *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
|
||||||
|
*/
|
||||||
|
void setOrientationTransformIfNeeded(MotionEvent event) {
|
||||||
|
// negative coordinates bug b/143901881
|
||||||
|
if (event.getX() < 0 || event.getY() < 0) {
|
||||||
|
event.setLocation(Math.max(0, event.getX()), Math.max(0, event.getY()));
|
||||||
|
}
|
||||||
|
mOrientationTouchTransformer.transform(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enableMultipleRegions(boolean enable) {
|
||||||
|
mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
|
||||||
|
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getQuickStepStartingRotation());
|
||||||
|
if (enable && !mInOverview && !TestProtocol.sDisableSensorRotation) {
|
||||||
|
// Clear any previous state from sensor manager
|
||||||
|
mSensorRotation = mCurrentAppRotation;
|
||||||
|
mOrientationListener.enable();
|
||||||
|
} else {
|
||||||
|
mOrientationListener.disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onStartGesture() {
|
||||||
|
if (mTaskListFrozen) {
|
||||||
|
// Prioritize whatever nav bar user touches once in quickstep
|
||||||
|
// This case is specifically when user changes what nav bar they are using mid
|
||||||
|
// quickswitch session before tasks list is unfrozen
|
||||||
|
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onEndTargetCalculated(GestureState.GestureEndTarget endTarget,
|
||||||
|
BaseActivityInterface activityInterface) {
|
||||||
|
if (endTarget == GestureState.GestureEndTarget.RECENTS) {
|
||||||
|
mInOverview = true;
|
||||||
|
if (!mTaskListFrozen) {
|
||||||
|
// If we're in landscape w/o ever quickswitching, show the navbar in landscape
|
||||||
|
enableMultipleRegions(true);
|
||||||
|
}
|
||||||
|
activityInterface.onExitOverview(this, mExitOverviewRunnable);
|
||||||
|
} else if (endTarget == GestureState.GestureEndTarget.HOME) {
|
||||||
|
enableMultipleRegions(false);
|
||||||
|
} else if (endTarget == GestureState.GestureEndTarget.NEW_TASK) {
|
||||||
|
if (mOrientationTouchTransformer.getQuickStepStartingRotation() == -1) {
|
||||||
|
// First gesture to start quickswitch
|
||||||
|
enableMultipleRegions(true);
|
||||||
|
} else {
|
||||||
|
notifySysuiOfCurrentRotation(
|
||||||
|
mOrientationTouchTransformer.getCurrentActiveRotation());
|
||||||
|
}
|
||||||
|
|
||||||
|
// A new gesture is starting, reset the current device rotation
|
||||||
|
// This is done under the assumption that the user won't rotate the phone and then
|
||||||
|
// quickswitch in the old orientation.
|
||||||
|
mPrioritizeDeviceRotation = false;
|
||||||
|
} else if (endTarget == GestureState.GestureEndTarget.LAST_TASK) {
|
||||||
|
if (!mTaskListFrozen) {
|
||||||
|
// touched nav bar but didn't go anywhere and not quickswitching, do nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifySysuiOfCurrentRotation(int rotation) {
|
||||||
|
UI_HELPER_EXECUTOR.execute(() -> SystemUiProxy.INSTANCE.get(mContext)
|
||||||
|
.onQuickSwitchToNewTask(rotation));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables/Enables multiple nav bars on {@link OrientationTouchTransformer} and then
|
||||||
|
* notifies system UI of the primary rotation the user is interacting with
|
||||||
|
*/
|
||||||
|
private void toggleSecondaryNavBarsForRotation() {
|
||||||
|
mOrientationTouchTransformer.setSingleActiveRegion(mDefaultDisplay.getInfo());
|
||||||
|
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCurrentActiveRotation() {
|
||||||
|
if (!mMode.hasGestures) {
|
||||||
|
// touch rotation should always match that of display for 3 button
|
||||||
|
return mDisplayRotation;
|
||||||
|
}
|
||||||
|
return mOrientationTouchTransformer.getCurrentActiveRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump(PrintWriter pw) {
|
||||||
|
pw.println("RotationTouchHelper:");
|
||||||
|
pw.println(" currentActiveRotation=" + getCurrentActiveRotation());
|
||||||
|
pw.println(" displayRotation=" + getDisplayRotation());
|
||||||
|
mOrientationTouchTransformer.dump(pw);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ package com.android.quickstep.interaction;
|
||||||
|
|
||||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||||
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
|
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
|
||||||
|
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
|
||||||
import static com.android.quickstep.BaseSwipeUpHandlerV2.MAX_SWIPE_DURATION;
|
import static com.android.quickstep.BaseSwipeUpHandlerV2.MAX_SWIPE_DURATION;
|
||||||
import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
|
import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
|
||||||
import static com.android.quickstep.interaction.TutorialController.TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
|
import static com.android.quickstep.interaction.TutorialController.TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
|
||||||
|
@ -110,6 +111,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||||
AnimatorListenerAdapter resetTaskView = new AnimatorListenerAdapter() {
|
AnimatorListenerAdapter resetTaskView = new AnimatorListenerAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationEnd(Animator animation, boolean isReverse) {
|
public void onAnimationEnd(Animator animation, boolean isReverse) {
|
||||||
|
mFakeIconView.setVisibility(View.INVISIBLE);
|
||||||
mFakeTaskView.setVisibility(View.INVISIBLE);
|
mFakeTaskView.setVisibility(View.INVISIBLE);
|
||||||
mFakeTaskView.setAlpha(1);
|
mFakeTaskView.setAlpha(1);
|
||||||
mRunningWindowAnim = null;
|
mRunningWindowAnim = null;
|
||||||
|
@ -131,6 +133,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
|
anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
|
||||||
|
anim.setViewAlpha(mFakeIconView, 0, ACCEL);
|
||||||
anim.addListener(resetTaskView);
|
anim.addListener(resetTaskView);
|
||||||
}
|
}
|
||||||
if (onEndRunnable != null) {
|
if (onEndRunnable != null) {
|
||||||
|
@ -202,7 +205,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||||
// derivative of the scroll interpolator at zero, ie. 2.
|
// derivative of the scroll interpolator at zero, ie. 2.
|
||||||
long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
|
long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
|
||||||
long duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
|
long duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
|
||||||
HomeAnimationFactory homeAnimFactory = new HomeAnimationFactory(null) {
|
HomeAnimationFactory homeAnimFactory = new HomeAnimationFactory() {
|
||||||
@Override
|
@Override
|
||||||
public AnimatorPlaybackController createActivityAnimationToHome() {
|
public AnimatorPlaybackController createActivityAnimationToHome() {
|
||||||
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
|
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
|
||||||
|
@ -218,6 +221,24 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||||
fakeHomeIconLeft + fakeHomeIconSizePx,
|
fakeHomeIconLeft + fakeHomeIconSizePx,
|
||||||
fakeHomeIconTop + fakeHomeIconSizePx);
|
fakeHomeIconTop + fakeHomeIconSizePx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(RectF rect, float progress, float radius) {
|
||||||
|
mFakeIconView.setVisibility(View.VISIBLE);
|
||||||
|
mFakeIconView.update(rect, progress,
|
||||||
|
1f - SHAPE_PROGRESS_DURATION /* shapeProgressStart */,
|
||||||
|
radius,
|
||||||
|
false, /* isOpening */
|
||||||
|
mFakeIconView, mDp,
|
||||||
|
false /* isVerticalBarLayout */);
|
||||||
|
mFakeIconView.setAlpha(1);
|
||||||
|
mFakeTaskView.setAlpha(getWindowAlpha(progress));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancel() {
|
||||||
|
mFakeIconView.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
RectFSpringAnim windowAnim = createWindowAnimationToHome(startShift, homeAnimFactory);
|
RectFSpringAnim windowAnim = createWindowAnimationToHome(startShift, homeAnimFactory);
|
||||||
windowAnim.start(mContext, velocityPxPerMs);
|
windowAnim.start(mContext, velocityPxPerMs);
|
||||||
|
|
|
@ -28,6 +28,7 @@ import androidx.annotation.CallSuper;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
|
import com.android.launcher3.views.ClipIconView;
|
||||||
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureAttemptCallback;
|
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureAttemptCallback;
|
||||||
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureAttemptCallback;
|
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureAttemptCallback;
|
||||||
|
|
||||||
|
@ -46,6 +47,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||||
final TextView mTitleTextView;
|
final TextView mTitleTextView;
|
||||||
final TextView mSubtitleTextView;
|
final TextView mSubtitleTextView;
|
||||||
final TextView mFeedbackView;
|
final TextView mFeedbackView;
|
||||||
|
final ClipIconView mFakeIconView;
|
||||||
final View mFakeTaskView;
|
final View mFakeTaskView;
|
||||||
final View mRippleView;
|
final View mRippleView;
|
||||||
final RippleDrawable mRippleDrawable;
|
final RippleDrawable mRippleDrawable;
|
||||||
|
@ -66,6 +68,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||||
mTitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_title_view);
|
mTitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_title_view);
|
||||||
mSubtitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_subtitle_view);
|
mSubtitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_subtitle_view);
|
||||||
mFeedbackView = rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_view);
|
mFeedbackView = rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_view);
|
||||||
|
mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view);
|
||||||
mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
|
mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
|
||||||
mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
|
mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
|
||||||
mRippleDrawable = (RippleDrawable) mRippleView.getBackground();
|
mRippleDrawable = (RippleDrawable) mRippleView.getBackground();
|
||||||
|
|
|
@ -27,7 +27,7 @@ import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGE
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
import com.android.launcher3.LauncherAppState;
|
import com.android.launcher3.LauncherAppState;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
|
@ -54,6 +54,7 @@ import com.android.systemui.shared.system.SysUiStatsLog;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.OptionalInt;
|
import java.util.OptionalInt;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class calls StatsLog compile time generated methods.
|
* This class calls StatsLog compile time generated methods.
|
||||||
|
@ -68,8 +69,6 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||||
private static final String TAG = "StatsLog";
|
private static final String TAG = "StatsLog";
|
||||||
private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.STATSLOG);
|
private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.STATSLOG);
|
||||||
|
|
||||||
private static Context sContext;
|
|
||||||
|
|
||||||
private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0);
|
private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0);
|
||||||
// LauncherAtom.ItemInfo.getDefaultInstance() should be used but until launcher proto migrates
|
// LauncherAtom.ItemInfo.getDefaultInstance() should be used but until launcher proto migrates
|
||||||
// from nano to lite, bake constant to prevent robo test failure.
|
// from nano to lite, bake constant to prevent robo test failure.
|
||||||
|
@ -77,8 +76,13 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||||
private static final int FOLDER_HIERARCHY_OFFSET = 100;
|
private static final int FOLDER_HIERARCHY_OFFSET = 100;
|
||||||
private static final int SEARCH_RESULT_HIERARCHY_OFFSET = 200;
|
private static final int SEARCH_RESULT_HIERARCHY_OFFSET = 200;
|
||||||
|
|
||||||
|
public static final CopyOnWriteArrayList<StatsLogConsumer> LOGS_CONSUMER =
|
||||||
|
new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
public StatsLogCompatManager(Context context) {
|
public StatsLogCompatManager(Context context) {
|
||||||
sContext = context;
|
mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -86,25 +90,12 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||||
return new StatsCompatLogger();
|
return new StatsCompatLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs a ranking event and accompanying {@link InstanceId} and package name.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void log(EventEnum rankingEvent, InstanceId instanceId, @Nullable String packageName,
|
|
||||||
int position) {
|
|
||||||
SysUiStatsLog.write(SysUiStatsLog.RANKING_SELECTED,
|
|
||||||
rankingEvent.getId() /* event_id = 1; */,
|
|
||||||
packageName /* package_name = 2; */,
|
|
||||||
instanceId.getId() /* instance_id = 3; */,
|
|
||||||
position /* position_picked = 4; */);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs the workspace layout information on the model thread.
|
* Logs the workspace layout information on the model thread.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void logSnapshot() {
|
public void logSnapshot() {
|
||||||
LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
|
LauncherAppState.getInstance(mContext).getModel().enqueueModelUpdateTask(
|
||||||
new SnapshotWorker());
|
new SnapshotWorker());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +166,7 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||||
private static class StatsCompatLogger implements StatsLogger {
|
private static class StatsCompatLogger implements StatsLogger {
|
||||||
|
|
||||||
private static final ItemInfo DEFAULT_ITEM_INFO = new ItemInfo();
|
private static final ItemInfo DEFAULT_ITEM_INFO = new ItemInfo();
|
||||||
|
|
||||||
private ItemInfo mItemInfo = DEFAULT_ITEM_INFO;
|
private ItemInfo mItemInfo = DEFAULT_ITEM_INFO;
|
||||||
private InstanceId mInstanceId = DEFAULT_INSTANCE_ID;
|
private InstanceId mInstanceId = DEFAULT_INSTANCE_ID;
|
||||||
private OptionalInt mRank = OptionalInt.empty();
|
private OptionalInt mRank = OptionalInt.empty();
|
||||||
|
@ -253,36 +245,35 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mItemInfo.container < 0) {
|
LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
|
||||||
// Item is not within a folder. Write to StatsLog in same thread.
|
if (mItemInfo.container < 0 || appState == null) {
|
||||||
write(event, mInstanceId, applyOverwrites(mItemInfo.buildProto()), mSrcState,
|
// Write log on the model thread so that logs do not go out of order
|
||||||
mDstState);
|
// (for eg: drop comes after drag)
|
||||||
|
Executors.MODEL_EXECUTOR.execute(
|
||||||
|
() -> write(event, applyOverwrites(mItemInfo.buildProto())));
|
||||||
} else {
|
} else {
|
||||||
// Item is inside the folder, fetch folder info in a BG thread
|
// Item is inside the folder, fetch folder info in a BG thread
|
||||||
// and then write to StatsLog.
|
// and then write to StatsLog.
|
||||||
LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
|
appState.getModel().enqueueModelUpdateTask(
|
||||||
new BaseModelUpdateTask() {
|
new BaseModelUpdateTask() {
|
||||||
@Override
|
@Override
|
||||||
public void execute(LauncherAppState app, BgDataModel dataModel,
|
public void execute(LauncherAppState app, BgDataModel dataModel,
|
||||||
AllAppsList apps) {
|
AllAppsList apps) {
|
||||||
FolderInfo folderInfo = dataModel.folders.get(mItemInfo.container);
|
FolderInfo folderInfo = dataModel.folders.get(mItemInfo.container);
|
||||||
write(event, mInstanceId,
|
write(event, applyOverwrites(mItemInfo.buildProto(folderInfo)));
|
||||||
applyOverwrites(mItemInfo.buildProto(folderInfo)),
|
|
||||||
mSrcState, mDstState);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private LauncherAtom.ItemInfo applyOverwrites(LauncherAtom.ItemInfo atomInfo) {
|
private LauncherAtom.ItemInfo applyOverwrites(LauncherAtom.ItemInfo atomInfo) {
|
||||||
LauncherAtom.ItemInfo.Builder itemInfoBuilder =
|
LauncherAtom.ItemInfo.Builder itemInfoBuilder = atomInfo.toBuilder();
|
||||||
(LauncherAtom.ItemInfo.Builder) atomInfo.toBuilder();
|
|
||||||
|
|
||||||
mRank.ifPresent(itemInfoBuilder::setRank);
|
mRank.ifPresent(itemInfoBuilder::setRank);
|
||||||
mContainerInfo.ifPresent(itemInfoBuilder::setContainerInfo);
|
mContainerInfo.ifPresent(itemInfoBuilder::setContainerInfo);
|
||||||
|
|
||||||
if (mFromState.isPresent() || mToState.isPresent() || mEditText.isPresent()) {
|
if (mFromState.isPresent() || mToState.isPresent() || mEditText.isPresent()) {
|
||||||
FolderIcon.Builder folderIconBuilder = (FolderIcon.Builder) itemInfoBuilder
|
FolderIcon.Builder folderIconBuilder = itemInfoBuilder
|
||||||
.getFolderIcon()
|
.getFolderIcon()
|
||||||
.toBuilder();
|
.toBuilder();
|
||||||
mFromState.ifPresent(folderIconBuilder::setFromLabelState);
|
mFromState.ifPresent(folderIconBuilder::setFromLabelState);
|
||||||
|
@ -293,8 +284,11 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||||
return itemInfoBuilder.build();
|
return itemInfoBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void write(EventEnum event, InstanceId instanceId, LauncherAtom.ItemInfo atomInfo,
|
@WorkerThread
|
||||||
int srcState, int dstState) {
|
private void write(EventEnum event, LauncherAtom.ItemInfo atomInfo) {
|
||||||
|
InstanceId instanceId = mInstanceId;
|
||||||
|
int srcState = mSrcState;
|
||||||
|
int dstState = mDstState;
|
||||||
if (IS_VERBOSE) {
|
if (IS_VERBOSE) {
|
||||||
String name = (event instanceof Enum) ? ((Enum) event).name() :
|
String name = (event instanceof Enum) ? ((Enum) event).name() :
|
||||||
event.getId() + "";
|
event.getId() + "";
|
||||||
|
@ -307,6 +301,10 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||||
atomInfo));
|
atomInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (StatsLogConsumer consumer : LOGS_CONSUMER) {
|
||||||
|
consumer.consume(event, atomInfo);
|
||||||
|
}
|
||||||
|
|
||||||
SysUiStatsLog.write(
|
SysUiStatsLog.write(
|
||||||
SysUiStatsLog.LAUNCHER_EVENT,
|
SysUiStatsLog.LAUNCHER_EVENT,
|
||||||
SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION /* deprecated */,
|
SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION /* deprecated */,
|
||||||
|
@ -446,7 +444,16 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||||
return "ALLAPPS";
|
return "ALLAPPS";
|
||||||
default:
|
default:
|
||||||
return "INVALID";
|
return "INVALID";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to get stats log while it is dispatched to the system
|
||||||
|
*/
|
||||||
|
public interface StatsLogConsumer {
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
void consume(EventEnum event, LauncherAtom.ItemInfo atomInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class LayoutUtils {
|
||||||
Rect taskSize = new Rect();
|
Rect taskSize = new Rect();
|
||||||
LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
|
LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
|
||||||
orientationHandler);
|
orientationHandler);
|
||||||
return (dp.heightPx - taskSize.height()) / 2;
|
return orientationHandler.getDistanceToBottomOfRect(dp, taskSize);
|
||||||
}
|
}
|
||||||
int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
|
int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
|
||||||
int spaceBetweenShelfAndRecents = (int) context.getResources().getDimension(
|
int spaceBetweenShelfAndRecents = (int) context.getResources().getDimension(
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:launcher="http://schemas.android.com/apk/res-auto"
|
xmlns:launcher="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:focusable="false">
|
||||||
|
|
||||||
<com.android.launcher3.CellLayout
|
<com.android.launcher3.CellLayout
|
||||||
android:id="@+id/workspace"
|
android:id="@+id/workspace"
|
||||||
|
|
|
@ -142,7 +142,7 @@
|
||||||
|
|
||||||
<item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
|
<item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
|
||||||
<item name="staggered_stiffness" type="dimen" format="float">150</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_damping_ratio" type="dimen" format="float">0.7</item>
|
||||||
<item name="hint_scale_stiffness" type="dimen" format="float">200</item>
|
<item name="hint_scale_stiffness" type="dimen" format="float">200</item>
|
||||||
|
|
|
@ -45,7 +45,6 @@ import androidx.annotation.Nullable;
|
||||||
import com.android.launcher3.LauncherSettings.Favorites;
|
import com.android.launcher3.LauncherSettings.Favorites;
|
||||||
import com.android.launcher3.logging.InstanceId;
|
import com.android.launcher3.logging.InstanceId;
|
||||||
import com.android.launcher3.logging.InstanceIdSequence;
|
import com.android.launcher3.logging.InstanceIdSequence;
|
||||||
import com.android.launcher3.model.AppLaunchTracker;
|
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
import com.android.launcher3.touch.ItemClickHandler;
|
import com.android.launcher3.touch.ItemClickHandler;
|
||||||
|
@ -82,7 +81,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
|
||||||
mIsSafeModeEnabled = TraceHelper.whitelistIpcs("isSafeMode",
|
mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
|
||||||
() -> getPackageManager().isSafeMode());
|
() -> getPackageManager().isSafeMode());
|
||||||
DefaultDisplay.INSTANCE.get(this).addChangeListener(this);
|
DefaultDisplay.INSTANCE.get(this).addChangeListener(this);
|
||||||
|
|
||||||
|
@ -154,8 +153,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||||
|
|
||||||
public abstract ActivityOptions getActivityLaunchOptions(View v);
|
public abstract ActivityOptions getActivityLaunchOptions(View v);
|
||||||
|
|
||||||
public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item,
|
public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item) {
|
||||||
@Nullable String sourceContainer) {
|
|
||||||
if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) {
|
if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) {
|
||||||
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
|
||||||
return false;
|
return false;
|
||||||
|
@ -176,17 +174,13 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||||
&& !((WorkspaceItemInfo) item).isPromise();
|
&& !((WorkspaceItemInfo) item).isPromise();
|
||||||
if (isShortcut) {
|
if (isShortcut) {
|
||||||
// Shortcuts need some special checks due to legacy reasons.
|
// Shortcuts need some special checks due to legacy reasons.
|
||||||
startShortcutIntentSafely(intent, optsBundle, item, sourceContainer);
|
startShortcutIntentSafely(intent, optsBundle, item);
|
||||||
} else if (user == null || user.equals(Process.myUserHandle())) {
|
} else if (user == null || user.equals(Process.myUserHandle())) {
|
||||||
// Could be launching some bookkeeping activity
|
// Could be launching some bookkeeping activity
|
||||||
startActivity(intent, optsBundle);
|
startActivity(intent, optsBundle);
|
||||||
AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(),
|
|
||||||
Process.myUserHandle(), sourceContainer);
|
|
||||||
} else {
|
} else {
|
||||||
getSystemService(LauncherApps.class).startMainActivity(
|
getSystemService(LauncherApps.class).startMainActivity(
|
||||||
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
|
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
|
||||||
AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(), user,
|
|
||||||
sourceContainer);
|
|
||||||
}
|
}
|
||||||
getUserEventDispatcher().logAppLaunch(v, intent, user);
|
getUserEventDispatcher().logAppLaunch(v, intent, user);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
|
@ -206,8 +200,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||||
.log(LAUNCHER_APP_LAUNCH_TAP);
|
.log(LAUNCHER_APP_LAUNCH_TAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info,
|
private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
|
||||||
@Nullable String sourceContainer) {
|
|
||||||
try {
|
try {
|
||||||
StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
|
StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
|
||||||
try {
|
try {
|
||||||
|
@ -221,8 +214,6 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||||
String id = ((WorkspaceItemInfo) info).getDeepShortcutId();
|
String id = ((WorkspaceItemInfo) info).getDeepShortcutId();
|
||||||
String packageName = intent.getPackage();
|
String packageName = intent.getPackage();
|
||||||
startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user);
|
startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user);
|
||||||
AppLaunchTracker.INSTANCE.get(this).onStartShortcut(packageName, id, info.user,
|
|
||||||
sourceContainer);
|
|
||||||
} else {
|
} else {
|
||||||
// Could be launching some bookkeeping activity
|
// Could be launching some bookkeeping activity
|
||||||
startActivity(intent, optsBundle);
|
startActivity(intent, optsBundle);
|
||||||
|
|
|
@ -183,6 +183,10 @@ public abstract class BaseRecyclerView extends RecyclerView {
|
||||||
public void onScrollStateChanged(int state) {
|
public void onScrollStateChanged(int state) {
|
||||||
super.onScrollStateChanged(state);
|
super.onScrollStateChanged(state);
|
||||||
|
|
||||||
|
if (TestProtocol.sDebugTracing) {
|
||||||
|
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onScrollStateChanged: " + state);
|
||||||
|
}
|
||||||
|
|
||||||
if (state == SCROLL_STATE_IDLE) {
|
if (state == SCROLL_STATE_IDLE) {
|
||||||
AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
|
AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
|
||||||
}
|
}
|
||||||
|
@ -192,6 +196,10 @@ public abstract class BaseRecyclerView extends RecyclerView {
|
||||||
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
||||||
super.onInitializeAccessibilityNodeInfo(info);
|
super.onInitializeAccessibilityNodeInfo(info);
|
||||||
if (isLayoutSuppressed()) info.setScrollable(false);
|
if (isLayoutSuppressed()) info.setScrollable(false);
|
||||||
|
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||||
|
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS,
|
||||||
|
"onInitializeAccessibilityNodeInfo, scrollable: " + info.isScrollable());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -199,8 +207,12 @@ public abstract class BaseRecyclerView extends RecyclerView {
|
||||||
final boolean changing = frozen != isLayoutSuppressed();
|
final boolean changing = frozen != isLayoutSuppressed();
|
||||||
super.setLayoutFrozen(frozen);
|
super.setLayoutFrozen(frozen);
|
||||||
if (changing) {
|
if (changing) {
|
||||||
ActivityContext.lookupContext(getContext()).getDragLayer()
|
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||||
.sendAccessibilityEvent(TYPE_WINDOW_CONTENT_CHANGED);
|
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "setLayoutFrozen " + frozen
|
||||||
|
+ " @ " + Log.getStackTraceString(new Throwable()));
|
||||||
|
ActivityContext.lookupContext(getContext()).getDragLayer()
|
||||||
|
.sendAccessibilityEvent(TYPE_WINDOW_CONTENT_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -331,10 +331,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
// ignore events if they happen in padding area
|
// ignore events if they happen in padding area
|
||||||
if (event.getAction() == MotionEvent.ACTION_DOWN
|
if (event.getAction() == MotionEvent.ACTION_DOWN
|
||||||
&& (event.getY() < getPaddingTop()
|
&& shouldIgnoreTouchDown(event.getX(), event.getY())) {
|
||||||
|| event.getX() < getPaddingLeft()
|
|
||||||
|| event.getY() > getHeight() - getPaddingBottom()
|
|
||||||
|| event.getX() > getWidth() - getPaddingRight())) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isLongClickable()) {
|
if (isLongClickable()) {
|
||||||
|
@ -347,6 +344,16 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the touch down at the provided position be ignored
|
||||||
|
*/
|
||||||
|
protected boolean shouldIgnoreTouchDown(float x, float y) {
|
||||||
|
return y < getPaddingTop()
|
||||||
|
|| x < getPaddingLeft()
|
||||||
|
|| y > getHeight() - getPaddingBottom()
|
||||||
|
|| x > getWidth() - getPaddingRight();
|
||||||
|
}
|
||||||
|
|
||||||
void setStayPressed(boolean stayPressed) {
|
void setStayPressed(boolean stayPressed) {
|
||||||
mStayPressed = stayPressed;
|
mStayPressed = stayPressed;
|
||||||
refreshDrawableState();
|
refreshDrawableState();
|
||||||
|
|
|
@ -814,7 +814,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||||
|
|
||||||
if (grantResults.length > 0
|
if (grantResults.length > 0
|
||||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
startActivitySafely(v, intent, null, null);
|
startActivitySafely(v, intent, null);
|
||||||
} else {
|
} else {
|
||||||
// TODO: Show a snack bar with link to settings
|
// TODO: Show a snack bar with link to settings
|
||||||
Toast.makeText(this, getString(R.string.msg_no_phone_permission,
|
Toast.makeText(this, getString(R.string.msg_no_phone_permission,
|
||||||
|
@ -923,6 +923,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||||
DiscoveryBounce.showForHomeIfNeeded(this);
|
DiscoveryBounce.showForHomeIfNeeded(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void handlePendingActivityRequest() { }
|
||||||
|
|
||||||
private void logStopAndResume(int command) {
|
private void logStopAndResume(int command) {
|
||||||
int pageIndex = mWorkspace.isOverlayShown() ? -1 : mWorkspace.getCurrentPage();
|
int pageIndex = mWorkspace.isOverlayShown() ? -1 : mWorkspace.getCurrentPage();
|
||||||
|
@ -1423,7 +1424,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||||
if (!isInState(NORMAL)) {
|
if (!isInState(NORMAL)) {
|
||||||
// Only change state, if not already the same. This prevents cancelling any
|
// Only change state, if not already the same. This prevents cancelling any
|
||||||
// animations running as part of resume
|
// animations running as part of resume
|
||||||
mStateManager.goToState(NORMAL);
|
mStateManager.goToState(NORMAL, mStateManager.shouldAnimateStateChange(),
|
||||||
|
this::handlePendingActivityRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the apps view
|
// Reset the apps view
|
||||||
|
@ -1860,13 +1862,12 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean startActivitySafely(View v, Intent intent, ItemInfo item,
|
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
|
||||||
@Nullable String sourceContainer) {
|
|
||||||
if (!hasBeenResumed()) {
|
if (!hasBeenResumed()) {
|
||||||
// Workaround an issue where the WM launch animation is clobbered when finishing the
|
// Workaround an issue where the WM launch animation is clobbered when finishing the
|
||||||
// recents animation into launcher. Defer launching the activity until Launcher is
|
// recents animation into launcher. Defer launching the activity until Launcher is
|
||||||
// next resumed.
|
// next resumed.
|
||||||
addOnResumeCallback(() -> startActivitySafely(v, intent, item, sourceContainer));
|
addOnResumeCallback(() -> startActivitySafely(v, intent, item));
|
||||||
if (mOnDeferredActivityLaunchCallback != null) {
|
if (mOnDeferredActivityLaunchCallback != null) {
|
||||||
mOnDeferredActivityLaunchCallback.run();
|
mOnDeferredActivityLaunchCallback.run();
|
||||||
mOnDeferredActivityLaunchCallback = null;
|
mOnDeferredActivityLaunchCallback = null;
|
||||||
|
@ -1874,7 +1875,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean success = super.startActivitySafely(v, intent, item, sourceContainer);
|
boolean success = super.startActivitySafely(v, intent, item);
|
||||||
if (success && v instanceof BubbleTextView) {
|
if (success && v instanceof BubbleTextView) {
|
||||||
// This is set to the view that launched the activity that navigated the user away
|
// This is set to the view that launched the activity that navigated the user away
|
||||||
// from launcher. Since there is no callback for when the activity has finished
|
// from launcher. Since there is no callback for when the activity has finished
|
||||||
|
|
|
@ -58,7 +58,7 @@ import com.android.launcher3.pm.InstallSessionTracker;
|
||||||
import com.android.launcher3.pm.PackageInstallInfo;
|
import com.android.launcher3.pm.PackageInstallInfo;
|
||||||
import com.android.launcher3.pm.UserCache;
|
import com.android.launcher3.pm.UserCache;
|
||||||
import com.android.launcher3.shortcuts.ShortcutRequest;
|
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.ItemInfoMatcher;
|
||||||
import com.android.launcher3.util.LooperExecutor;
|
import com.android.launcher3.util.LooperExecutor;
|
||||||
import com.android.launcher3.util.PackageUserKey;
|
import com.android.launcher3.util.PackageUserKey;
|
||||||
|
@ -410,7 +410,7 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
|
||||||
enqueueModelUpdateTask(new BaseModelUpdateTask() {
|
enqueueModelUpdateTask(new BaseModelUpdateTask() {
|
||||||
@Override
|
@Override
|
||||||
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
|
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
|
||||||
final IntSparseArrayMap<Boolean> removedIds = new IntSparseArrayMap<>();
|
final IntSet removedIds = new IntSet();
|
||||||
synchronized (dataModel) {
|
synchronized (dataModel) {
|
||||||
for (ItemInfo info : dataModel.itemsIdMap) {
|
for (ItemInfo info : dataModel.itemsIdMap) {
|
||||||
if (info instanceof WorkspaceItemInfo
|
if (info instanceof WorkspaceItemInfo
|
||||||
|
@ -418,13 +418,13 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
|
||||||
&& user.equals(info.user)
|
&& user.equals(info.user)
|
||||||
&& info.getIntent() != null
|
&& info.getIntent() != null
|
||||||
&& TextUtils.equals(packageName, info.getIntent().getPackage())) {
|
&& TextUtils.equals(packageName, info.getIntent().getPackage())) {
|
||||||
removedIds.put(info.id, true /* remove */);
|
removedIds.add(info.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!removedIds.isEmpty()) {
|
if (!removedIds.isEmpty()) {
|
||||||
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedIds, false));
|
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedIds));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -250,7 +250,8 @@ public abstract class LauncherState implements BaseState<LauncherState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
|
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
|
||||||
if (this != NORMAL || !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
|
if ((this != NORMAL && this != HINT_STATE)
|
||||||
|
|| !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
|
||||||
return DEFAULT_ALPHA_PROVIDER;
|
return DEFAULT_ALPHA_PROVIDER;
|
||||||
}
|
}
|
||||||
final int centerPage = launcher.getWorkspace().getNextPage();
|
final int centerPage = launcher.getWorkspace().getNextPage();
|
||||||
|
|
|
@ -39,7 +39,7 @@ import com.android.launcher3.dragndrop.DragOptions;
|
||||||
import com.android.launcher3.logging.FileLog;
|
import com.android.launcher3.logging.FileLog;
|
||||||
import com.android.launcher3.logging.LoggerUtils;
|
import com.android.launcher3.logging.LoggerUtils;
|
||||||
import com.android.launcher3.logging.StatsLogManager;
|
import com.android.launcher3.logging.StatsLogManager;
|
||||||
import com.android.launcher3.model.AppLaunchTracker;
|
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||||
|
@ -218,13 +218,16 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
||||||
public void onDrop(DragObject d, DragOptions options) {
|
public void onDrop(DragObject d, DragOptions options) {
|
||||||
// Defer onComplete
|
// Defer onComplete
|
||||||
d.dragSource = new DeferredOnComplete(d.dragSource, getContext());
|
d.dragSource = new DeferredOnComplete(d.dragSource, getContext());
|
||||||
|
|
||||||
super.onDrop(d, options);
|
super.onDrop(d, options);
|
||||||
|
StatsLogger logger = mStatsLogManager.logger().withInstanceId(d.logInstanceId);
|
||||||
|
if (d.originalDragInfo != null) {
|
||||||
|
logger.withItemInfo(d.originalDragInfo);
|
||||||
|
}
|
||||||
if (mCurrentAccessibilityAction == UNINSTALL) {
|
if (mCurrentAccessibilityAction == UNINSTALL) {
|
||||||
mStatsLogManager.logger().withInstanceId(d.logInstanceId)
|
logger.log(LAUNCHER_ITEM_DROPPED_ON_UNINSTALL);
|
||||||
.log(LAUNCHER_ITEM_DROPPED_ON_UNINSTALL);
|
|
||||||
} else if (mCurrentAccessibilityAction == DISMISS_PREDICTION) {
|
} else if (mCurrentAccessibilityAction == DISMISS_PREDICTION) {
|
||||||
mStatsLogManager.logger().withInstanceId(d.logInstanceId)
|
logger.log(LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST);
|
||||||
.log(LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,8 +286,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (mCurrentAccessibilityAction == DISMISS_PREDICTION) {
|
if (mCurrentAccessibilityAction == DISMISS_PREDICTION) {
|
||||||
AppLaunchTracker.INSTANCE.get(getContext()).onDismissApp(info.getTargetComponent(),
|
// We sent the log event, nothing else left to do
|
||||||
info.user, AppLaunchTracker.CONTAINER_PREDICTIONS);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// else: mCurrentAccessibilityAction == UNINSTALL
|
// else: mCurrentAccessibilityAction == UNINSTALL
|
||||||
|
|
|
@ -309,7 +309,9 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||||
// In portrait, we want the pages spaced such that there is no
|
// In portrait, we want the pages spaced such that there is no
|
||||||
// overhang of the previous / next page into the current page viewport.
|
// overhang of the previous / next page into the current page viewport.
|
||||||
// We assume symmetrical padding in portrait mode.
|
// We assume symmetrical padding in portrait mode.
|
||||||
setPageSpacing(Math.max(grid.edgeMarginPx, padding.left + 1));
|
int maxInsets = Math.max(insets.left, insets.right);
|
||||||
|
int maxPadding = Math.max(grid.edgeMarginPx, padding.left + 1);
|
||||||
|
setPageSpacing(Math.max(maxInsets, maxPadding));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||||
protected final BaseDraggingActivity mLauncher;
|
protected final BaseDraggingActivity mLauncher;
|
||||||
protected final AdapterHolder[] mAH;
|
protected final AdapterHolder[] mAH;
|
||||||
private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle());
|
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 AllAppsStore mAllAppsStore = new AllAppsStore();
|
||||||
|
|
||||||
private final Paint mNavBarScrimPaint;
|
private final Paint mNavBarScrimPaint;
|
||||||
|
|
|
@ -41,7 +41,6 @@ import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.BubbleTextView;
|
import com.android.launcher3.BubbleTextView;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem;
|
import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem;
|
||||||
import com.android.launcher3.model.AppLaunchTracker;
|
|
||||||
import com.android.launcher3.model.data.AppInfo;
|
import com.android.launcher3.model.data.AppInfo;
|
||||||
import com.android.launcher3.util.PackageManagerHelper;
|
import com.android.launcher3.util.PackageManagerHelper;
|
||||||
|
|
||||||
|
@ -270,7 +269,7 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
|
||||||
View searchMarketView = mLayoutInflater.inflate(R.layout.all_apps_search_market,
|
View searchMarketView = mLayoutInflater.inflate(R.layout.all_apps_search_market,
|
||||||
parent, false);
|
parent, false);
|
||||||
searchMarketView.setOnClickListener(v -> mLauncher.startActivitySafely(
|
searchMarketView.setOnClickListener(v -> mLauncher.startActivitySafely(
|
||||||
v, mMarketSearchIntent, null, AppLaunchTracker.CONTAINER_SEARCH));
|
v, mMarketSearchIntent, null));
|
||||||
return new ViewHolder(searchMarketView);
|
return new ViewHolder(searchMarketView);
|
||||||
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
||||||
return new ViewHolder(mLayoutInflater.inflate(
|
return new ViewHolder(mLayoutInflater.inflate(
|
||||||
|
|
|
@ -28,7 +28,6 @@ import android.widget.TextView.OnEditorActionListener;
|
||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.ExtendedEditText;
|
import com.android.launcher3.ExtendedEditText;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.model.AppLaunchTracker;
|
|
||||||
import com.android.launcher3.util.ComponentKey;
|
import com.android.launcher3.util.ComponentKey;
|
||||||
import com.android.launcher3.util.PackageManagerHelper;
|
import com.android.launcher3.util.PackageManagerHelper;
|
||||||
|
|
||||||
|
@ -112,8 +111,8 @@ public class AllAppsSearchBarController
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return mLauncher.startActivitySafely(v,
|
return mLauncher.startActivitySafely(v,
|
||||||
PackageManagerHelper.getMarketSearchIntent(mLauncher, query), null,
|
PackageManagerHelper.getMarketSearchIntent(mLauncher, query), null
|
||||||
AppLaunchTracker.CONTAINER_SEARCH);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -75,6 +75,9 @@ public class AccessibilityManagerCompat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendScrollFinishedEventToTest(Context context) {
|
public static void sendScrollFinishedEventToTest(Context context) {
|
||||||
|
if (TestProtocol.sDebugTracing) {
|
||||||
|
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "sendScrollFinishedEventToTest");
|
||||||
|
}
|
||||||
final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
|
final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
|
||||||
if (accessibilityManager == null) return;
|
if (accessibilityManager == null) return;
|
||||||
|
|
||||||
|
@ -94,6 +97,9 @@ public class AccessibilityManagerCompat {
|
||||||
AccessibilityEvent.TYPE_ANNOUNCEMENT);
|
AccessibilityEvent.TYPE_ANNOUNCEMENT);
|
||||||
e.setClassName(eventTag);
|
e.setClassName(eventTag);
|
||||||
e.setParcelableData(data);
|
e.setParcelableData(data);
|
||||||
|
if (TestProtocol.sDebugTracing) {
|
||||||
|
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "sendEventToTest " + e);
|
||||||
|
}
|
||||||
accessibilityManager.sendAccessibilityEvent(e);
|
accessibilityManager.sendAccessibilityEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -241,9 +241,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||||
mFolderName.setSelectAllOnFocus(true);
|
mFolderName.setSelectAllOnFocus(true);
|
||||||
mFolderName.setInputType(mFolderName.getInputType()
|
mFolderName.setInputType(mFolderName.getInputType()
|
||||||
& ~InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
|
& ~InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
|
||||||
& ~InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
|
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
|
||||||
| InputType.TYPE_TEXT_FLAG_CAP_WORDS);
|
| InputType.TYPE_TEXT_FLAG_CAP_WORDS);
|
||||||
mFolderName.forceDisableSuggestions(!FeatureFlags.FOLDER_NAME_SUGGEST.get());
|
mFolderName.forceDisableSuggestions(true);
|
||||||
|
|
||||||
mFooter = findViewById(R.id.folder_footer);
|
mFooter = findViewById(R.id.folder_footer);
|
||||||
|
|
||||||
|
@ -741,7 +741,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected View getAccessibilityInitialFocusView() {
|
protected View getAccessibilityInitialFocusView() {
|
||||||
return mContent.getFirstItem();
|
View firstItem = mContent.getFirstItem();
|
||||||
|
return firstItem != null ? firstItem : super.getAccessibilityInitialFocusView();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeComplete(boolean wasAnimated) {
|
private void closeComplete(boolean wasAnimated) {
|
||||||
|
|
|
@ -126,7 +126,7 @@ public class LauncherPreviewRenderer {
|
||||||
*/
|
*/
|
||||||
public static class PreviewContext extends ContextWrapper {
|
public static class PreviewContext extends ContextWrapper {
|
||||||
|
|
||||||
private static final Set<MainThreadInitializedObject> WHITELIST = new HashSet<>(
|
private final Set<MainThreadInitializedObject> mAllowedObjects = new HashSet<>(
|
||||||
Arrays.asList(UserCache.INSTANCE, InstallSessionHelper.INSTANCE,
|
Arrays.asList(UserCache.INSTANCE, InstallSessionHelper.INSTANCE,
|
||||||
LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
|
LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
|
||||||
CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE));
|
CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE));
|
||||||
|
@ -160,7 +160,7 @@ public class LauncherPreviewRenderer {
|
||||||
*/
|
*/
|
||||||
public <T> T getObject(MainThreadInitializedObject<T> mainThreadInitializedObject,
|
public <T> T getObject(MainThreadInitializedObject<T> mainThreadInitializedObject,
|
||||||
MainThreadInitializedObject.ObjectProvider<T> provider) {
|
MainThreadInitializedObject.ObjectProvider<T> provider) {
|
||||||
if (!WHITELIST.contains(mainThreadInitializedObject)) {
|
if (!mAllowedObjects.contains(mainThreadInitializedObject)) {
|
||||||
throw new IllegalStateException("Leaking unknown objects");
|
throw new IllegalStateException("Leaking unknown objects");
|
||||||
}
|
}
|
||||||
if (mainThreadInitializedObject == LauncherAppState.INSTANCE) {
|
if (mainThreadInitializedObject == LauncherAppState.INSTANCE) {
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package com.android.launcher3.logging;
|
package com.android.launcher3.logging;
|
||||||
|
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
|
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_CLOSE_DOWN;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_CLOSE_DOWN;
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_OPEN_UP;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_OPEN_UP;
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE;
|
||||||
|
@ -23,8 +22,6 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
|
import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
|
||||||
import com.android.launcher3.logger.LauncherAtom.FromState;
|
import com.android.launcher3.logger.LauncherAtom.FromState;
|
||||||
|
@ -403,19 +400,6 @@ public class StatsLogManager implements ResourceBasedOverride {
|
||||||
return mgr;
|
return mgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an event with ranked-choice information along with package. Does nothing if event.getId()
|
|
||||||
* <= 0.
|
|
||||||
*
|
|
||||||
* @param rankingEvent an enum implementing EventEnum interface.
|
|
||||||
* @param instanceId An identifier obtained from an InstanceIdSequence.
|
|
||||||
* @param packageName the package name of the relevant app, if known (null otherwise).
|
|
||||||
* @param position the position picked.
|
|
||||||
*/
|
|
||||||
public void log(EventEnum rankingEvent, InstanceId instanceId, @Nullable String packageName,
|
|
||||||
int position) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs snapshot, or impression of the current workspace.
|
* Logs snapshot, or impression of the current workspace.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -17,13 +17,7 @@ package com.android.launcher3.model;
|
||||||
|
|
||||||
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
|
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
|
||||||
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.os.UserHandle;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
|
||||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||||
import com.android.launcher3.util.ResourceBasedOverride;
|
import com.android.launcher3.util.ResourceBasedOverride;
|
||||||
|
|
||||||
|
@ -32,28 +26,8 @@ import com.android.launcher3.util.ResourceBasedOverride;
|
||||||
*/
|
*/
|
||||||
public class AppLaunchTracker implements ResourceBasedOverride {
|
public class AppLaunchTracker implements ResourceBasedOverride {
|
||||||
|
|
||||||
/**
|
|
||||||
* Derived from LauncherEvent proto.
|
|
||||||
* TODO: Use proper descriptive constants
|
|
||||||
*/
|
|
||||||
public static final String CONTAINER_DEFAULT = Integer.toString(ContainerType.WORKSPACE);
|
|
||||||
public static final String CONTAINER_ALL_APPS = Integer.toString(ContainerType.ALLAPPS);
|
|
||||||
public static final String CONTAINER_PREDICTIONS = Integer.toString(ContainerType.PREDICTION);
|
|
||||||
public static final String CONTAINER_SEARCH = Integer.toString(ContainerType.SEARCHRESULT);
|
|
||||||
public static final String CONTAINER_OVERVIEW = Integer.toString(ContainerType.OVERVIEW);
|
|
||||||
|
|
||||||
|
|
||||||
public static final MainThreadInitializedObject<AppLaunchTracker> INSTANCE =
|
public static final MainThreadInitializedObject<AppLaunchTracker> INSTANCE =
|
||||||
forOverride(AppLaunchTracker.class, R.string.app_launch_tracker_class);
|
forOverride(AppLaunchTracker.class, R.string.app_launch_tracker_class);
|
||||||
|
|
||||||
public void onStartShortcut(String packageName, String shortcutId, UserHandle user,
|
|
||||||
@Nullable String container) { }
|
|
||||||
|
|
||||||
public void onStartApp(ComponentName componentName, UserHandle user,
|
|
||||||
@Nullable String container) { }
|
|
||||||
|
|
||||||
public void onDismissApp(ComponentName componentName, UserHandle user,
|
|
||||||
@Nullable String container){}
|
|
||||||
|
|
||||||
public void onReturnedToHome() { }
|
public void onReturnedToHome() { }
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -348,6 +349,19 @@ public class BgDataModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
public interface Callbacks {
|
||||||
// If the launcher has permission to access deep shortcuts.
|
// If the launcher has permission to access deep shortcuts.
|
||||||
int FLAG_HAS_SHORTCUT_PERMISSION = 1 << 0;
|
int FLAG_HAS_SHORTCUT_PERMISSION = 1 << 0;
|
||||||
|
|
|
@ -21,7 +21,6 @@ import android.os.UserHandle;
|
||||||
import com.android.launcher3.LauncherAppState;
|
import com.android.launcher3.LauncherAppState;
|
||||||
import com.android.launcher3.LauncherSettings;
|
import com.android.launcher3.LauncherSettings;
|
||||||
import com.android.launcher3.icons.IconCache;
|
import com.android.launcher3.icons.IconCache;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
|
||||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -48,23 +47,18 @@ public class CacheDataUpdatedTask extends BaseModelUpdateTask {
|
||||||
@Override
|
@Override
|
||||||
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
|
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
|
||||||
IconCache iconCache = app.getIconCache();
|
IconCache iconCache = app.getIconCache();
|
||||||
|
|
||||||
|
|
||||||
ArrayList<WorkspaceItemInfo> updatedShortcuts = new ArrayList<>();
|
ArrayList<WorkspaceItemInfo> updatedShortcuts = new ArrayList<>();
|
||||||
|
|
||||||
synchronized (dataModel) {
|
synchronized (dataModel) {
|
||||||
for (ItemInfo info : dataModel.itemsIdMap) {
|
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
|
||||||
if (info instanceof WorkspaceItemInfo && mUser.equals(info.user)) {
|
ComponentName cn = si.getTargetComponent();
|
||||||
WorkspaceItemInfo si = (WorkspaceItemInfo) info;
|
if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
|
||||||
ComponentName cn = si.getTargetComponent();
|
&& isValidShortcut(si) && cn != null
|
||||||
if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
|
&& mPackages.contains(cn.getPackageName())) {
|
||||||
&& isValidShortcut(si) && cn != null
|
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
|
||||||
&& mPackages.contains(cn.getPackageName())) {
|
updatedShortcuts.add(si);
|
||||||
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
|
|
||||||
updatedShortcuts.add(si);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
apps.updateIconsAndLabels(mPackages, mUser);
|
apps.updateIconsAndLabels(mPackages, mUser);
|
||||||
}
|
}
|
||||||
bindUpdatedWorkspaceItems(updatedShortcuts);
|
bindUpdatedWorkspaceItems(updatedShortcuts);
|
||||||
|
|
|
@ -20,8 +20,6 @@ import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
|
||||||
import com.android.launcher3.LauncherAppState;
|
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.ItemInfo;
|
||||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||||
import com.android.launcher3.model.data.PromiseAppInfo;
|
import com.android.launcher3.model.data.PromiseAppInfo;
|
||||||
|
@ -70,21 +68,18 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask {
|
||||||
|
|
||||||
synchronized (dataModel) {
|
synchronized (dataModel) {
|
||||||
final HashSet<ItemInfo> updates = new HashSet<>();
|
final HashSet<ItemInfo> updates = new HashSet<>();
|
||||||
for (ItemInfo info : dataModel.itemsIdMap) {
|
dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> {
|
||||||
if (info instanceof WorkspaceItemInfo) {
|
ComponentName cn = si.getTargetComponent();
|
||||||
WorkspaceItemInfo si = (WorkspaceItemInfo) info;
|
if (si.hasPromiseIconUi() && (cn != null)
|
||||||
ComponentName cn = si.getTargetComponent();
|
&& mInstallInfo.packageName.equals(cn.getPackageName())) {
|
||||||
if (si.hasPromiseIconUi() && (cn != null)
|
si.setInstallProgress(mInstallInfo.progress);
|
||||||
&& mInstallInfo.packageName.equals(cn.getPackageName())) {
|
if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) {
|
||||||
si.setInstallProgress(mInstallInfo.progress);
|
// Mark this info as broken.
|
||||||
if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) {
|
si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE;
|
||||||
// Mark this info as broken.
|
|
||||||
si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE;
|
|
||||||
}
|
|
||||||
updates.add(si);
|
|
||||||
}
|
}
|
||||||
|
updates.add(si);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
for (LauncherAppWidgetInfo widget : dataModel.appWidgets) {
|
for (LauncherAppWidgetInfo widget : dataModel.appWidgets) {
|
||||||
if (widget.providerName.getPackageName().equals(mInstallInfo.packageName)) {
|
if (widget.providerName.getPackageName().equals(mInstallInfo.packageName)) {
|
||||||
|
@ -94,12 +89,7 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!updates.isEmpty()) {
|
if (!updates.isEmpty()) {
|
||||||
scheduleCallbackTask(new CallbackTask() {
|
scheduleCallbackTask(callbacks -> callbacks.bindRestoreItemsChange(updates));
|
||||||
@Override
|
|
||||||
public void execute(Callbacks callbacks) {
|
|
||||||
callbacks.bindRestoreItemsChange(updates);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
import com.android.launcher3.pm.UserCache;
|
import com.android.launcher3.pm.UserCache;
|
||||||
import com.android.launcher3.shortcuts.ShortcutRequest;
|
import com.android.launcher3.shortcuts.ShortcutRequest;
|
||||||
import com.android.launcher3.util.FlagOp;
|
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.ItemInfoMatcher;
|
||||||
import com.android.launcher3.util.PackageManagerHelper;
|
import com.android.launcher3.util.PackageManagerHelper;
|
||||||
import com.android.launcher3.util.PackageUserKey;
|
import com.android.launcher3.util.PackageUserKey;
|
||||||
|
@ -92,9 +92,11 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
|
||||||
|
|
||||||
final String[] packages = mPackages;
|
final String[] packages = mPackages;
|
||||||
final int N = packages.length;
|
final int N = packages.length;
|
||||||
FlagOp flagOp = FlagOp.NO_OP;
|
final FlagOp flagOp;
|
||||||
final HashSet<String> packageSet = new HashSet<>(Arrays.asList(packages));
|
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<>();
|
final HashSet<ComponentName> removedComponents = new HashSet<>();
|
||||||
|
|
||||||
switch (mOp) {
|
switch (mOp) {
|
||||||
|
@ -158,19 +160,22 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
|
||||||
flagOp = ums.isUserQuiet(mUser)
|
flagOp = ums.isUserQuiet(mUser)
|
||||||
? FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER)
|
? FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER)
|
||||||
: FlagOp.removeFlag(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);
|
appsList.updateDisabledFlags(matcher, flagOp);
|
||||||
|
|
||||||
// We are not synchronizing here, as int operations are atomic
|
// We are not synchronizing here, as int operations are atomic
|
||||||
appsList.setFlags(FLAG_QUIET_MODE_ENABLED, ums.isAnyProfileQuietModeEnabled());
|
appsList.setFlags(FLAG_QUIET_MODE_ENABLED, ums.isAnyProfileQuietModeEnabled());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
flagOp = FlagOp.NO_OP;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bindApplicationsIfNeeded();
|
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
|
// Update shortcut infos
|
||||||
if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
|
if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
|
||||||
|
@ -180,118 +185,118 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
|
||||||
// For system apps, package manager send OP_UPDATE when an app is enabled.
|
// For system apps, package manager send OP_UPDATE when an app is enabled.
|
||||||
final boolean isNewApkAvailable = mOp == OP_ADD || mOp == OP_UPDATE;
|
final boolean isNewApkAvailable = mOp == OP_ADD || mOp == OP_UPDATE;
|
||||||
synchronized (dataModel) {
|
synchronized (dataModel) {
|
||||||
for (ItemInfo info : dataModel.itemsIdMap) {
|
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
|
||||||
if (info instanceof WorkspaceItemInfo && mUser.equals(info.user)) {
|
|
||||||
WorkspaceItemInfo si = (WorkspaceItemInfo) info;
|
|
||||||
boolean infoUpdated = false;
|
|
||||||
boolean shortcutUpdated = false;
|
|
||||||
|
|
||||||
// Update shortcuts which use iconResource.
|
boolean infoUpdated = false;
|
||||||
if ((si.iconResource != null)
|
boolean shortcutUpdated = false;
|
||||||
&& packageSet.contains(si.iconResource.packageName)) {
|
|
||||||
LauncherIcons li = LauncherIcons.obtain(context);
|
// Update shortcuts which use iconResource.
|
||||||
BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
|
if ((si.iconResource != null)
|
||||||
li.recycle();
|
&& packageSet.contains(si.iconResource.packageName)) {
|
||||||
if (iconInfo != null) {
|
LauncherIcons li = LauncherIcons.obtain(context);
|
||||||
si.bitmap = iconInfo;
|
BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
|
||||||
infoUpdated = true;
|
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 (si.isPromise() && isNewApkAvailable) {
|
||||||
if (cn != null && matcher.matches(si, cn)) {
|
boolean isTargetValid = true;
|
||||||
String packageName = cn.getPackageName();
|
if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
||||||
|
List<ShortcutInfo> shortcut =
|
||||||
if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)) {
|
new ShortcutRequest(context, mUser)
|
||||||
removedShortcuts.put(si.id, false);
|
.forPackage(cn.getPackageName(),
|
||||||
if (mOp == OP_REMOVE) {
|
si.getDeepShortcutId())
|
||||||
continue;
|
.query(ShortcutRequest.PINNED);
|
||||||
}
|
if (shortcut.isEmpty()) {
|
||||||
}
|
isTargetValid = false;
|
||||||
|
|
||||||
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;
|
|
||||||
} else {
|
} else {
|
||||||
si.status = WorkspaceItemInfo.DEFAULT;
|
si.updateFromDeepShortcutInfo(shortcut.get(0), context);
|
||||||
infoUpdated = true;
|
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)) {
|
if (updateWorkspaceItemIntent(context, si, packageName)) {
|
||||||
infoUpdated = true;
|
infoUpdated = true;
|
||||||
|
} else if (si.hasPromiseIconUi()) {
|
||||||
|
removedShortcuts.add(si.id);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
} else if (!isTargetValid) {
|
||||||
|
removedShortcuts.add(si.id);
|
||||||
if (isNewApkAvailable &&
|
FileLog.e(TAG, "Restored shortcut no longer valid "
|
||||||
si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
|
+ si.getIntent());
|
||||||
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
|
return;
|
||||||
|
} else {
|
||||||
|
si.status = WorkspaceItemInfo.DEFAULT;
|
||||||
infoUpdated = true;
|
infoUpdated = true;
|
||||||
}
|
}
|
||||||
|
} else if (isNewApkAvailable && removedComponents.contains(cn)) {
|
||||||
int oldRuntimeFlags = si.runtimeStatusFlags;
|
if (updateWorkspaceItemIntent(context, si, packageName)) {
|
||||||
si.runtimeStatusFlags = flagOp.apply(si.runtimeStatusFlags);
|
infoUpdated = true;
|
||||||
if (si.runtimeStatusFlags != oldRuntimeFlags) {
|
|
||||||
shortcutUpdated = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (infoUpdated || shortcutUpdated) {
|
if (isNewApkAvailable
|
||||||
updatedWorkspaceItems.add(si);
|
&& 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'
|
int oldRuntimeFlags = si.runtimeStatusFlags;
|
||||||
// if the widget has a config activity. In case there is no config
|
si.runtimeStatusFlags = flagOp.apply(si.runtimeStatusFlags);
|
||||||
// activity, it will be marked as 'restored' during bind.
|
if (si.runtimeStatusFlags != oldRuntimeFlags) {
|
||||||
widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
|
shortcutUpdated = true;
|
||||||
|
|
||||||
widgets.add(widgetInfo);
|
|
||||||
getModelWriter().updateItemInDatabase(widgetInfo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
bindUpdatedWorkspaceItems(updatedWorkspaceItems);
|
||||||
if (!removedShortcuts.isEmpty()) {
|
if (!removedShortcuts.isEmpty()) {
|
||||||
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedShortcuts, false));
|
deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedShortcuts));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!widgets.isEmpty()) {
|
if (!widgets.isEmpty()) {
|
||||||
|
@ -319,7 +324,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
|
||||||
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
|
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
|
||||||
ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
|
ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
|
||||||
.or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
|
.or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
|
||||||
.and(ItemInfoMatcher.ofItemIds(removedShortcuts, true));
|
.and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
|
||||||
deleteAndBindComponentsRemoved(removeMatch);
|
deleteAndBindComponentsRemoved(removeMatch);
|
||||||
|
|
||||||
// Remove any queued items from the install queue
|
// Remove any queued items from the install queue
|
||||||
|
|
|
@ -21,7 +21,6 @@ import android.os.UserHandle;
|
||||||
|
|
||||||
import com.android.launcher3.LauncherAppState;
|
import com.android.launcher3.LauncherAppState;
|
||||||
import com.android.launcher3.LauncherSettings;
|
import com.android.launcher3.LauncherSettings;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
|
||||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||||
import com.android.launcher3.shortcuts.ShortcutRequest;
|
import com.android.launcher3.shortcuts.ShortcutRequest;
|
||||||
|
@ -58,14 +57,14 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask {
|
||||||
MultiHashMap<ShortcutKey, WorkspaceItemInfo> keyToShortcutInfo = new MultiHashMap<>();
|
MultiHashMap<ShortcutKey, WorkspaceItemInfo> keyToShortcutInfo = new MultiHashMap<>();
|
||||||
HashSet<String> allIds = new HashSet<>();
|
HashSet<String> allIds = new HashSet<>();
|
||||||
|
|
||||||
for (ItemInfo itemInfo : dataModel.itemsIdMap) {
|
synchronized (dataModel) {
|
||||||
if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
|
||||||
WorkspaceItemInfo si = (WorkspaceItemInfo) itemInfo;
|
if ((si.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
|
||||||
if (mPackageName.equals(si.getIntent().getPackage()) && si.user.equals(mUser)) {
|
&& mPackageName.equals(si.getIntent().getPackage())) {
|
||||||
keyToShortcutInfo.addToList(ShortcutKey.fromItemInfo(si), si);
|
keyToShortcutInfo.addToList(ShortcutKey.fromItemInfo(si), si);
|
||||||
allIds.add(si.getDeepShortcutId());
|
allIds.add(si.getDeepShortcutId());
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
final ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
|
final ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
|
||||||
|
|
|
@ -23,7 +23,6 @@ import android.os.UserHandle;
|
||||||
|
|
||||||
import com.android.launcher3.LauncherAppState;
|
import com.android.launcher3.LauncherAppState;
|
||||||
import com.android.launcher3.LauncherSettings;
|
import com.android.launcher3.LauncherSettings;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
|
||||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||||
import com.android.launcher3.shortcuts.ShortcutRequest;
|
import com.android.launcher3.shortcuts.ShortcutRequest;
|
||||||
|
@ -73,27 +72,27 @@ public class UserLockStateChangedTask extends BaseModelUpdateTask {
|
||||||
ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
|
ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
|
||||||
HashSet<ShortcutKey> removedKeys = new HashSet<>();
|
HashSet<ShortcutKey> removedKeys = new HashSet<>();
|
||||||
|
|
||||||
for (ItemInfo itemInfo : dataModel.itemsIdMap) {
|
synchronized (dataModel) {
|
||||||
if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
|
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
|
||||||
&& mUser.equals(itemInfo.user)) {
|
if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
||||||
WorkspaceItemInfo si = (WorkspaceItemInfo) itemInfo;
|
if (mIsUserUnlocked) {
|
||||||
if (mIsUserUnlocked) {
|
ShortcutKey key = ShortcutKey.fromItemInfo(si);
|
||||||
ShortcutKey key = ShortcutKey.fromItemInfo(si);
|
ShortcutInfo shortcut = pinnedShortcuts.get(key);
|
||||||
ShortcutInfo shortcut = pinnedShortcuts.get(key);
|
// We couldn't verify the shortcut during loader. If its no longer available
|
||||||
// We couldn't verify the shortcut during loader. If its no longer available
|
// (probably due to clear data), delete the workspace item as well
|
||||||
// (probably due to clear data), delete the workspace item as well
|
if (shortcut == null) {
|
||||||
if (shortcut == null) {
|
removedKeys.add(key);
|
||||||
removedKeys.add(key);
|
return;
|
||||||
continue;
|
}
|
||||||
|
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;
|
updatedWorkspaceItemInfos.add(si);
|
||||||
si.updateFromDeepShortcutInfo(shortcut, context);
|
|
||||||
app.getIconCache().getShortcutIcon(si, shortcut);
|
|
||||||
} else {
|
|
||||||
si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
|
|
||||||
}
|
}
|
||||||
updatedWorkspaceItemInfos.add(si);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
|
bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
|
||||||
if (!removedKeys.isEmpty()) {
|
if (!removedKeys.isEmpty()) {
|
||||||
|
|
|
@ -53,6 +53,7 @@ import com.android.launcher3.logger.LauncherAtom.SettingsContainer;
|
||||||
import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer;
|
import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer;
|
||||||
import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer;
|
import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer;
|
||||||
import com.android.launcher3.model.ModelWriter;
|
import com.android.launcher3.model.ModelWriter;
|
||||||
|
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||||
import com.android.launcher3.util.ContentWriter;
|
import com.android.launcher3.util.ContentWriter;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -285,6 +286,13 @@ public class ItemInfo {
|
||||||
.orElse(LauncherAtom.Application.newBuilder()));
|
.orElse(LauncherAtom.Application.newBuilder()));
|
||||||
break;
|
break;
|
||||||
case ITEM_TYPE_DEEP_SHORTCUT:
|
case ITEM_TYPE_DEEP_SHORTCUT:
|
||||||
|
itemBuilder
|
||||||
|
.setShortcut(nullableComponent
|
||||||
|
.map(component -> LauncherAtom.Shortcut.newBuilder()
|
||||||
|
.setShortcutName(component.flattenToShortString())
|
||||||
|
.setShortcutId(ShortcutKey.fromItemInfo(this).getId()))
|
||||||
|
.orElse(LauncherAtom.Shortcut.newBuilder()));
|
||||||
|
break;
|
||||||
case ITEM_TYPE_SHORTCUT:
|
case ITEM_TYPE_SHORTCUT:
|
||||||
itemBuilder
|
itemBuilder
|
||||||
.setShortcut(nullableComponent
|
.setShortcut(nullableComponent
|
||||||
|
|
|
@ -174,7 +174,7 @@ public abstract class SystemShortcut<T extends BaseDraggingActivity> extends Ite
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
Intent intent = new PackageManagerHelper(view.getContext()).getMarketIntent(
|
Intent intent = new PackageManagerHelper(view.getContext()).getMarketIntent(
|
||||||
mItemInfo.getTargetComponent().getPackageName());
|
mItemInfo.getTargetComponent().getPackageName());
|
||||||
mTarget.startActivitySafely(view, intent, mItemInfo, null);
|
mTarget.startActivitySafely(view, intent, mItemInfo);
|
||||||
AbstractFloatingView.closeAllOpenViews(mTarget);
|
AbstractFloatingView.closeAllOpenViews(mTarget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package com.android.launcher3.secondarydisplay;
|
package com.android.launcher3.secondarydisplay;
|
||||||
|
|
||||||
import static com.android.launcher3.model.AppLaunchTracker.CONTAINER_ALL_APPS;
|
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
import android.app.ActivityOptions;
|
import android.app.ActivityOptions;
|
||||||
|
@ -327,7 +325,7 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity
|
||||||
if (intent == null) {
|
if (intent == null) {
|
||||||
throw new IllegalArgumentException("Input must have a valid intent");
|
throw new IllegalArgumentException("Input must have a valid intent");
|
||||||
}
|
}
|
||||||
startActivitySafely(v, intent, item, CONTAINER_ALL_APPS);
|
startActivitySafely(v, intent, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.android.launcher3.BubbleTextView;
|
import com.android.launcher3.BubbleTextView;
|
||||||
|
@ -106,12 +105,12 @@ public class DeepShortcutTextView extends BubbleTextView {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouchEvent(MotionEvent ev) {
|
protected boolean shouldIgnoreTouchDown(float x, float y) {
|
||||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
// Show toast if user touches the drag handle (long clicks still start the drag).
|
||||||
// Show toast if user touches the drag handle (long clicks still start the drag).
|
mShowInstructionToast = mDragHandleBounds.contains((int) x, (int) y);
|
||||||
mShowInstructionToast = mDragHandleBounds.contains((int) ev.getX(), (int) ev.getY());
|
|
||||||
}
|
// assume the whole view as clickable
|
||||||
return super.onTouchEvent(ev);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -33,6 +33,7 @@ import com.android.launcher3.LauncherAppState;
|
||||||
import com.android.launcher3.LauncherState;
|
import com.android.launcher3.LauncherState;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.util.ResourceBasedOverride;
|
import com.android.launcher3.util.ResourceBasedOverride;
|
||||||
|
import com.android.launcher3.widget.WidgetsFullSheet;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
@ -92,6 +93,11 @@ public class TestInformationHandler implements ResourceBasedOverride {
|
||||||
l -> l.getAppsView().getActiveRecyclerView().getCurrentScrollY());
|
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: {
|
case TestProtocol.REQUEST_WINDOW_INSETS: {
|
||||||
return getUIProperty(Bundle::putParcelable, a -> {
|
return getUIProperty(Bundle::putParcelable, a -> {
|
||||||
WindowInsets insets = a.getWindow()
|
WindowInsets insets = a.getWindow()
|
||||||
|
|
|
@ -81,6 +81,7 @@ public final class TestProtocol {
|
||||||
public static final String REQUEST_UNFREEZE_APP_LIST = "unfreeze-app-list";
|
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_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_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_WINDOW_INSETS = "window-insets";
|
||||||
public static final String REQUEST_PID = "pid";
|
public static final String REQUEST_PID = "pid";
|
||||||
public static final String REQUEST_TOTAL_PSS_KB = "total_pss";
|
public static final String REQUEST_TOTAL_PSS_KB = "total_pss";
|
||||||
|
@ -106,4 +107,5 @@ public final class TestProtocol {
|
||||||
public static final String PAUSE_NOT_DETECTED = "b/139891609";
|
public static final String PAUSE_NOT_DETECTED = "b/139891609";
|
||||||
public static final String OVERIEW_NOT_ALLAPPS = "b/156095088";
|
public static final String OVERIEW_NOT_ALLAPPS = "b/156095088";
|
||||||
public static final String NO_SWIPE_TO_HOME = "b/158017601";
|
public static final String NO_SWIPE_TO_HOME = "b/158017601";
|
||||||
|
public static final String NO_SCROLL_END_WIDGETS = "b/160238801";
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ package com.android.launcher3.touch;
|
||||||
import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET;
|
import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET;
|
||||||
import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET;
|
import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET;
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
|
||||||
import static com.android.launcher3.model.AppLaunchTracker.CONTAINER_ALL_APPS;
|
|
||||||
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
|
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
|
||||||
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
|
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
|
||||||
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_QUIET_USER;
|
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_QUIET_USER;
|
||||||
|
@ -37,8 +36,6 @@ import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.android.launcher3.BubbleTextView;
|
import com.android.launcher3.BubbleTextView;
|
||||||
import com.android.launcher3.Launcher;
|
import com.android.launcher3.Launcher;
|
||||||
import com.android.launcher3.LauncherAppWidgetProviderInfo;
|
import com.android.launcher3.LauncherAppWidgetProviderInfo;
|
||||||
|
@ -72,13 +69,9 @@ public class ItemClickHandler {
|
||||||
/**
|
/**
|
||||||
* Instance used for click handling on items
|
* Instance used for click handling on items
|
||||||
*/
|
*/
|
||||||
public static final OnClickListener INSTANCE = getInstance(null);
|
public static final OnClickListener INSTANCE = ItemClickHandler::onClick;
|
||||||
|
|
||||||
public static final OnClickListener getInstance(String sourceContainer) {
|
private static void onClick(View v) {
|
||||||
return v -> onClick(v, sourceContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void onClick(View v, String sourceContainer) {
|
|
||||||
// Make sure that rogue clicks don't get through while allapps is launching, or after the
|
// Make sure that rogue clicks don't get through while allapps is launching, or after the
|
||||||
// view has detached (it's possible for this to happen if the view is removed mid touch).
|
// view has detached (it's possible for this to happen if the view is removed mid touch).
|
||||||
if (v.getWindowToken() == null) return;
|
if (v.getWindowToken() == null) return;
|
||||||
|
@ -88,14 +81,14 @@ public class ItemClickHandler {
|
||||||
|
|
||||||
Object tag = v.getTag();
|
Object tag = v.getTag();
|
||||||
if (tag instanceof WorkspaceItemInfo) {
|
if (tag instanceof WorkspaceItemInfo) {
|
||||||
onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher, sourceContainer);
|
onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher);
|
||||||
} else if (tag instanceof FolderInfo) {
|
} else if (tag instanceof FolderInfo) {
|
||||||
if (v instanceof FolderIcon) {
|
if (v instanceof FolderIcon) {
|
||||||
onClickFolderIcon(v);
|
onClickFolderIcon(v);
|
||||||
}
|
}
|
||||||
} else if (tag instanceof AppInfo) {
|
} else if (tag instanceof AppInfo) {
|
||||||
startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher,
|
startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher
|
||||||
sourceContainer == null ? CONTAINER_ALL_APPS: sourceContainer);
|
);
|
||||||
} else if (tag instanceof LauncherAppWidgetInfo) {
|
} else if (tag instanceof LauncherAppWidgetInfo) {
|
||||||
if (v instanceof PendingAppWidgetHostView) {
|
if (v instanceof PendingAppWidgetHostView) {
|
||||||
onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
|
onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
|
||||||
|
@ -191,7 +184,7 @@ public class ItemClickHandler {
|
||||||
|
|
||||||
// Fallback to using custom market intent.
|
// Fallback to using custom market intent.
|
||||||
Intent intent = new PackageManagerHelper(launcher).getMarketIntent(packageName);
|
Intent intent = new PackageManagerHelper(launcher).getMarketIntent(packageName);
|
||||||
launcher.startActivitySafely(v, intent, item, null);
|
launcher.startActivitySafely(v, intent, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -199,8 +192,7 @@ public class ItemClickHandler {
|
||||||
*
|
*
|
||||||
* @param v The view that was clicked. Must be a tagged with a {@link WorkspaceItemInfo}.
|
* @param v The view that was clicked. Must be a tagged with a {@link WorkspaceItemInfo}.
|
||||||
*/
|
*/
|
||||||
public static void onClickAppShortcut(View v, WorkspaceItemInfo shortcut, Launcher launcher,
|
public static void onClickAppShortcut(View v, WorkspaceItemInfo shortcut, Launcher launcher) {
|
||||||
@Nullable String sourceContainer) {
|
|
||||||
if (shortcut.isDisabled()) {
|
if (shortcut.isDisabled()) {
|
||||||
final int disabledFlags = shortcut.runtimeStatusFlags
|
final int disabledFlags = shortcut.runtimeStatusFlags
|
||||||
& WorkspaceItemInfo.FLAG_DISABLED_MASK;
|
& WorkspaceItemInfo.FLAG_DISABLED_MASK;
|
||||||
|
@ -241,11 +233,10 @@ public class ItemClickHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start activities
|
// Start activities
|
||||||
startAppShortcutOrInfoActivity(v, shortcut, launcher, sourceContainer);
|
startAppShortcutOrInfoActivity(v, shortcut, launcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher,
|
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
|
||||||
@Nullable String sourceContainer) {
|
|
||||||
TestLogging.recordEvent(
|
TestLogging.recordEvent(
|
||||||
TestProtocol.SEQUENCE_MAIN, "start: startAppShortcutOrInfoActivity");
|
TestProtocol.SEQUENCE_MAIN, "start: startAppShortcutOrInfoActivity");
|
||||||
Intent intent;
|
Intent intent;
|
||||||
|
@ -274,6 +265,6 @@ public class ItemClickHandler {
|
||||||
// Preload the icon to reduce latency b/w swapping the floating view with the original.
|
// Preload the icon to reduce latency b/w swapping the floating view with the original.
|
||||||
FloatingIconView.fetchIcon(launcher, v, item, true /* isOpening */);
|
FloatingIconView.fetchIcon(launcher, v, item, true /* isOpening */);
|
||||||
}
|
}
|
||||||
launcher.startActivitySafely(v, intent, item, sourceContainer);
|
launcher.startActivitySafely(v, intent, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package com.android.launcher3.touch;
|
package com.android.launcher3.touch;
|
||||||
|
|
||||||
import static android.widget.ListPopupWindow.WRAP_CONTENT;
|
import static android.widget.ListPopupWindow.WRAP_CONTENT;
|
||||||
|
|
||||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
|
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
|
||||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
|
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
|
||||||
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
|
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
|
||||||
|
@ -33,6 +34,7 @@ import android.view.View;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.PagedView;
|
import com.android.launcher3.PagedView;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.util.OverScroller;
|
import com.android.launcher3.util.OverScroller;
|
||||||
|
@ -237,7 +239,8 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout) {
|
public int getTaskMenuLayoutOrientation(boolean canRecentsActivityRotate,
|
||||||
|
LinearLayout taskMenuLayout) {
|
||||||
return LinearLayout.HORIZONTAL;
|
return LinearLayout.HORIZONTAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,4 +263,10 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
|
||||||
}
|
}
|
||||||
return new ChildBounds(childHeight, childWidth, childBottom, childLeft);
|
return new ChildBounds(childHeight, childWidth, childBottom, childLeft);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SuspiciousNameCombination")
|
||||||
|
@Override
|
||||||
|
public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
|
||||||
|
return rect.left;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,8 +94,9 @@ public interface PagedOrientationHandler {
|
||||||
float getTaskMenuX(float x, View thumbnailView);
|
float getTaskMenuX(float x, View thumbnailView);
|
||||||
float getTaskMenuY(float y, View thumbnailView);
|
float getTaskMenuY(float y, View thumbnailView);
|
||||||
int getTaskMenuWidth(View view);
|
int getTaskMenuWidth(View view);
|
||||||
int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout);
|
int getTaskMenuLayoutOrientation(boolean canRecentsActivityRotate, LinearLayout taskMenuLayout);
|
||||||
void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp);
|
void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp);
|
||||||
|
int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps the velocity from the coordinate plane of the foreground app to that
|
* Maps the velocity from the coordinate plane of the foreground app to that
|
||||||
|
|
|
@ -32,6 +32,7 @@ import android.view.View;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.PagedView;
|
import com.android.launcher3.PagedView;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.util.OverScroller;
|
import com.android.launcher3.util.OverScroller;
|
||||||
|
@ -236,8 +237,9 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout) {
|
public int getTaskMenuLayoutOrientation(boolean canRecentsActivityRotate,
|
||||||
return taskMenuLayout.getOrientation();
|
LinearLayout taskMenuLayout) {
|
||||||
|
return canRecentsActivityRotate ? taskMenuLayout.getOrientation() : LinearLayout.VERTICAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -257,4 +259,9 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
|
||||||
}
|
}
|
||||||
return new ChildBounds(childWidth, childHeight, childRight, childTop);
|
return new ChildBounds(childWidth, childHeight, childRight, childTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
|
||||||
|
return dp.heightPx - rect.bottom;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,11 @@ package com.android.launcher3.touch;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
|
import android.graphics.Rect;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
|
|
||||||
public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
|
public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
|
||||||
|
@ -77,4 +79,9 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
|
||||||
view.setTranslationX(0);
|
view.setTranslationX(0);
|
||||||
view.setTranslationY(translation);
|
view.setTranslationY(translation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
|
||||||
|
return dp.widthPx - rect.right;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,11 +81,10 @@ public interface ItemInfoMatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new matcher which returns the opposite boolean value of the provided
|
* Returns a new matcher with returns the opposite value of this.
|
||||||
* {@param matcher}.
|
|
||||||
*/
|
*/
|
||||||
static ItemInfoMatcher not(ItemInfoMatcher matcher) {
|
default ItemInfoMatcher negate() {
|
||||||
return (info, cn) -> !matcher.matches(info, cn);
|
return (info, cn) -> !matches(info, cn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ItemInfoMatcher ofUser(UserHandle user) {
|
static ItemInfoMatcher ofUser(UserHandle user) {
|
||||||
|
@ -105,7 +104,10 @@ public interface ItemInfoMatcher {
|
||||||
keys.contains(ShortcutKey.fromItemInfo(info));
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class MainThreadInitializedObject<T> {
|
||||||
|
|
||||||
if (mValue == null) {
|
if (mValue == null) {
|
||||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||||
mValue = TraceHelper.whitelistIpcs("main.thread.object",
|
mValue = TraceHelper.allowIpcs("main.thread.object",
|
||||||
() -> mProvider.get(context.getApplicationContext()));
|
() -> mProvider.get(context.getApplicationContext()));
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -64,7 +64,7 @@ public class OnboardingPrefs<T extends Launcher> {
|
||||||
|
|
||||||
private static final Map<String, Integer> MAX_COUNTS;
|
private static final Map<String, Integer> MAX_COUNTS;
|
||||||
static {
|
static {
|
||||||
Map<String, Integer> maxCounts = new ArrayMap<>(3);
|
Map<String, Integer> maxCounts = new ArrayMap<>(4);
|
||||||
maxCounts.put(HOME_BOUNCE_COUNT, 3);
|
maxCounts.put(HOME_BOUNCE_COUNT, 3);
|
||||||
maxCounts.put(SHELF_BOUNCE_COUNT, 3);
|
maxCounts.put(SHELF_BOUNCE_COUNT, 3);
|
||||||
maxCounts.put(ALL_APPS_COUNT, 5);
|
maxCounts.put(ALL_APPS_COUNT, 5);
|
||||||
|
|
|
@ -78,7 +78,7 @@ public class TraceHelper {
|
||||||
* Temporarily ignore blocking binder calls for the duration of this {@link Supplier}.
|
* Temporarily ignore blocking binder calls for the duration of this {@link Supplier}.
|
||||||
*/
|
*/
|
||||||
@MainThread
|
@MainThread
|
||||||
public static <T> T whitelistIpcs(String rpcName, Supplier<T> supplier) {
|
public static <T> T allowIpcs(String rpcName, Supplier<T> supplier) {
|
||||||
Object traceToken = INSTANCE.beginSection(rpcName, FLAG_IGNORE_BINDERS);
|
Object traceToken = INSTANCE.beginSection(rpcName, FLAG_IGNORE_BINDERS);
|
||||||
try {
|
try {
|
||||||
return supplier.get();
|
return supplier.get();
|
||||||
|
|
|
@ -292,6 +292,9 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||||
|
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||||
|
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "BaseDragLayer: " + ev);
|
||||||
|
}
|
||||||
switch (ev.getAction()) {
|
switch (ev.getAction()) {
|
||||||
case ACTION_DOWN: {
|
case ACTION_DOWN: {
|
||||||
if ((mTouchDispatchState & TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS) != 0) {
|
if ((mTouchDispatchState & TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS) != 0) {
|
||||||
|
@ -602,13 +605,13 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||||
*/
|
*/
|
||||||
private boolean computeAllowSysuiScrims(@Nullable WallpaperInfo newWallpaperInfo) {
|
private boolean computeAllowSysuiScrims(@Nullable WallpaperInfo newWallpaperInfo) {
|
||||||
if (newWallpaperInfo == null) {
|
if (newWallpaperInfo == null) {
|
||||||
// New wallpaper is static, not live. Thus, blacklist isn't applicable.
|
// Static wallpapers need scrim unless determined otherwise by wallpaperColors.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ComponentName newWallpaper = newWallpaperInfo.getComponent();
|
ComponentName newWallpaper = newWallpaperInfo.getComponent();
|
||||||
for (String wallpaperWithoutScrim : mWallpapersWithoutSysuiScrims) {
|
for (String wallpaperWithoutScrim : mWallpapersWithoutSysuiScrims) {
|
||||||
if (newWallpaper.equals(ComponentName.unflattenFromString(wallpaperWithoutScrim))) {
|
if (newWallpaper.equals(ComponentName.unflattenFromString(wallpaperWithoutScrim))) {
|
||||||
// New wallpaper is blacklisted from showing a scrim.
|
// New wallpaper does not need a scrim.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import android.graphics.drawable.Drawable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup.MarginLayoutParams;
|
||||||
import android.view.ViewOutlineProvider;
|
import android.view.ViewOutlineProvider;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -44,8 +45,6 @@ import androidx.dynamicanimation.animation.SpringAnimation;
|
||||||
import androidx.dynamicanimation.animation.SpringForce;
|
import androidx.dynamicanimation.animation.SpringForce;
|
||||||
|
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.InsettableFrameLayout.LayoutParams;
|
|
||||||
import com.android.launcher3.Launcher;
|
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
|
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
|
||||||
|
@ -94,7 +93,6 @@ public class ClipIconView extends View implements ClipPathView {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final Launcher mLauncher;
|
|
||||||
private final int mBlurSizeOutline;
|
private final int mBlurSizeOutline;
|
||||||
private final boolean mIsRtl;
|
private final boolean mIsRtl;
|
||||||
|
|
||||||
|
@ -128,7 +126,6 @@ public class ClipIconView extends View implements ClipPathView {
|
||||||
|
|
||||||
public ClipIconView(Context context, AttributeSet attrs, int defStyleAttr) {
|
public ClipIconView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
mLauncher = Launcher.getLauncher(context);
|
|
||||||
mBlurSizeOutline = getResources().getDimensionPixelSize(
|
mBlurSizeOutline = getResources().getDimensionPixelSize(
|
||||||
R.dimen.blur_size_medium_outline);
|
R.dimen.blur_size_medium_outline);
|
||||||
mIsRtl = Utilities.isRtl(getResources());
|
mIsRtl = Utilities.isRtl(getResources());
|
||||||
|
@ -143,10 +140,41 @@ public class ClipIconView extends View implements ClipPathView {
|
||||||
.setStiffness(SpringForce.STIFFNESS_LOW));
|
.setStiffness(SpringForce.STIFFNESS_LOW));
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
|
/**
|
||||||
boolean isOpening, float scale, float minSize, LayoutParams parentLp,
|
* Update the icon UI to match the provided parameters during an animation frame
|
||||||
boolean isVerticalBarLayout) {
|
*/
|
||||||
DeviceProfile dp = mLauncher.getDeviceProfile();
|
public void update(RectF rect, float progress, float shapeProgressStart,
|
||||||
|
float cornerRadius, boolean isOpening, View container,
|
||||||
|
DeviceProfile dp, boolean isVerticalBarLayout) {
|
||||||
|
|
||||||
|
MarginLayoutParams lp = (MarginLayoutParams) container.getLayoutParams();
|
||||||
|
|
||||||
|
float dX = mIsRtl
|
||||||
|
? rect.left - (dp.widthPx - lp.getMarginStart() - lp.width)
|
||||||
|
: rect.left - lp.getMarginStart();
|
||||||
|
float dY = rect.top - lp.topMargin;
|
||||||
|
container.setTranslationX(dX);
|
||||||
|
container.setTranslationY(dY);
|
||||||
|
|
||||||
|
float minSize = Math.min(lp.width, lp.height);
|
||||||
|
float scaleX = rect.width() / minSize;
|
||||||
|
float scaleY = rect.height() / minSize;
|
||||||
|
float scale = Math.max(1f, Math.min(scaleX, scaleY));
|
||||||
|
|
||||||
|
update(rect, progress, shapeProgressStart, cornerRadius, isOpening, scale,
|
||||||
|
minSize, lp, isVerticalBarLayout, dp);
|
||||||
|
|
||||||
|
container.setPivotX(0);
|
||||||
|
container.setPivotY(0);
|
||||||
|
container.setScaleX(scale);
|
||||||
|
container.setScaleY(scale);
|
||||||
|
|
||||||
|
container.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
|
||||||
|
boolean isOpening, float scale, float minSize, MarginLayoutParams parentLp,
|
||||||
|
boolean isVerticalBarLayout, DeviceProfile dp) {
|
||||||
float dX = mIsRtl
|
float dX = mIsRtl
|
||||||
? rect.left - (dp.widthPx - parentLp.getMarginStart() - parentLp.width)
|
? rect.left - (dp.widthPx - parentLp.getMarginStart() - parentLp.width)
|
||||||
: rect.left - parentLp.getMarginStart();
|
: rect.left - parentLp.getMarginStart();
|
||||||
|
@ -228,8 +256,11 @@ public class ClipIconView extends View implements ClipPathView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setIcon(@Nullable Drawable drawable, int iconOffset, LayoutParams lp, boolean isOpening,
|
/**
|
||||||
boolean isVerticalBarLayout) {
|
* Sets the icon for this view as part of initial setup
|
||||||
|
*/
|
||||||
|
public void setIcon(@Nullable Drawable drawable, int iconOffset, MarginLayoutParams lp,
|
||||||
|
boolean isOpening, boolean isVerticalBarLayout, DeviceProfile dp) {
|
||||||
mIsAdaptiveIcon = drawable instanceof AdaptiveIconDrawable;
|
mIsAdaptiveIcon = drawable instanceof AdaptiveIconDrawable;
|
||||||
if (mIsAdaptiveIcon) {
|
if (mIsAdaptiveIcon) {
|
||||||
boolean isFolderIcon = drawable instanceof FolderAdaptiveIcon;
|
boolean isFolderIcon = drawable instanceof FolderAdaptiveIcon;
|
||||||
|
@ -264,15 +295,14 @@ public class ClipIconView extends View implements ClipPathView {
|
||||||
Utilities.scaleRectAboutCenter(mStartRevealRect, IconShape.getNormalizationScale());
|
Utilities.scaleRectAboutCenter(mStartRevealRect, IconShape.getNormalizationScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
float aspectRatio = mLauncher.getDeviceProfile().aspectRatio;
|
|
||||||
if (isVerticalBarLayout) {
|
if (isVerticalBarLayout) {
|
||||||
lp.width = (int) Math.max(lp.width, lp.height * aspectRatio);
|
lp.width = (int) Math.max(lp.width, lp.height * dp.aspectRatio);
|
||||||
} else {
|
} else {
|
||||||
lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
|
lp.height = (int) Math.max(lp.height, lp.width * dp.aspectRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
int left = mIsRtl
|
int left = mIsRtl
|
||||||
? mLauncher.getDeviceProfile().widthPx - lp.getMarginStart() - lp.width
|
? dp.widthPx - lp.getMarginStart() - lp.width
|
||||||
: lp.leftMargin;
|
: lp.leftMargin;
|
||||||
layout(left, lp.topMargin, left + lp.width, lp.topMargin + lp.height);
|
layout(left, lp.topMargin, left + lp.width, lp.topMargin + lp.height);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import static com.android.launcher3.Utilities.getBadge;
|
||||||
import static com.android.launcher3.Utilities.getFullDrawable;
|
import static com.android.launcher3.Utilities.getFullDrawable;
|
||||||
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
|
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
|
||||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||||
|
import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
@ -47,7 +48,6 @@ import androidx.annotation.UiThread;
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
import com.android.launcher3.BubbleTextView;
|
import com.android.launcher3.BubbleTextView;
|
||||||
import com.android.launcher3.DeviceProfile;
|
|
||||||
import com.android.launcher3.InsettableFrameLayout;
|
import com.android.launcher3.InsettableFrameLayout;
|
||||||
import com.android.launcher3.Launcher;
|
import com.android.launcher3.Launcher;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
|
@ -144,32 +144,8 @@ public class FloatingIconView extends FrameLayout implements
|
||||||
public void update(RectF rect, float alpha, float progress, float shapeProgressStart,
|
public void update(RectF rect, float alpha, float progress, float shapeProgressStart,
|
||||||
float cornerRadius, boolean isOpening) {
|
float cornerRadius, boolean isOpening) {
|
||||||
setAlpha(alpha);
|
setAlpha(alpha);
|
||||||
|
mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, isOpening,
|
||||||
InsettableFrameLayout.LayoutParams lp =
|
this, mLauncher.getDeviceProfile(), mIsVerticalBarLayout);
|
||||||
(InsettableFrameLayout.LayoutParams) getLayoutParams();
|
|
||||||
|
|
||||||
DeviceProfile dp = mLauncher.getDeviceProfile();
|
|
||||||
float dX = mIsRtl
|
|
||||||
? rect.left - (dp.widthPx - lp.getMarginStart() - lp.width)
|
|
||||||
: rect.left - lp.getMarginStart();
|
|
||||||
float dY = rect.top - lp.topMargin;
|
|
||||||
setTranslationX(dX);
|
|
||||||
setTranslationY(dY);
|
|
||||||
|
|
||||||
float minSize = Math.min(lp.width, lp.height);
|
|
||||||
float scaleX = rect.width() / minSize;
|
|
||||||
float scaleY = rect.height() / minSize;
|
|
||||||
float scale = Math.max(1f, Math.min(scaleX, scaleY));
|
|
||||||
|
|
||||||
mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, isOpening, scale,
|
|
||||||
minSize, lp, mIsVerticalBarLayout);
|
|
||||||
|
|
||||||
setPivotX(0);
|
|
||||||
setPivotY(0);
|
|
||||||
setScaleX(scale);
|
|
||||||
setScaleY(scale);
|
|
||||||
|
|
||||||
invalidate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -336,7 +312,8 @@ public class FloatingIconView extends FrameLayout implements
|
||||||
final InsettableFrameLayout.LayoutParams lp =
|
final InsettableFrameLayout.LayoutParams lp =
|
||||||
(InsettableFrameLayout.LayoutParams) getLayoutParams();
|
(InsettableFrameLayout.LayoutParams) getLayoutParams();
|
||||||
mBadge = badge;
|
mBadge = badge;
|
||||||
mClipIconView.setIcon(drawable, iconOffset, lp, mIsOpening, mIsVerticalBarLayout);
|
mClipIconView.setIcon(drawable, iconOffset, lp, mIsOpening, mIsVerticalBarLayout,
|
||||||
|
mLauncher.getDeviceProfile());
|
||||||
if (drawable instanceof AdaptiveIconDrawable) {
|
if (drawable instanceof AdaptiveIconDrawable) {
|
||||||
final int originalHeight = lp.height;
|
final int originalHeight = lp.height;
|
||||||
final int originalWidth = lp.width;
|
final int originalWidth = lp.width;
|
||||||
|
@ -381,7 +358,7 @@ public class FloatingIconView extends FrameLayout implements
|
||||||
if (mIconLoadResult.isIconLoaded) {
|
if (mIconLoadResult.isIconLoaded) {
|
||||||
setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
|
setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
|
||||||
mIconLoadResult.iconOffset);
|
mIconLoadResult.iconOffset);
|
||||||
hideOriginalView(originalView);
|
setIconAndDotVisible(originalView, false);
|
||||||
} else {
|
} else {
|
||||||
mIconLoadResult.onIconLoaded = () -> {
|
mIconLoadResult.onIconLoaded = () -> {
|
||||||
if (cancellationSignal.isCanceled()) {
|
if (cancellationSignal.isCanceled()) {
|
||||||
|
@ -392,22 +369,13 @@ public class FloatingIconView extends FrameLayout implements
|
||||||
mIconLoadResult.iconOffset);
|
mIconLoadResult.iconOffset);
|
||||||
|
|
||||||
setVisibility(VISIBLE);
|
setVisibility(VISIBLE);
|
||||||
hideOriginalView(originalView);
|
setIconAndDotVisible(originalView, false);
|
||||||
};
|
};
|
||||||
mLoadIconSignal = cancellationSignal;
|
mLoadIconSignal = cancellationSignal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hideOriginalView(View originalView) {
|
|
||||||
if (originalView instanceof IconLabelDotView) {
|
|
||||||
((IconLabelDotView) originalView).setIconVisible(false);
|
|
||||||
((IconLabelDotView) originalView).setForceHideDot(true);
|
|
||||||
} else {
|
|
||||||
originalView.setVisibility(INVISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
@SuppressWarnings("WrongThread")
|
@SuppressWarnings("WrongThread")
|
||||||
private static int getOffsetForIconBounds(Launcher l, Drawable drawable, RectF position) {
|
private static int getOffsetForIconBounds(Launcher l, Drawable drawable, RectF position) {
|
||||||
|
@ -477,7 +445,7 @@ public class FloatingIconView extends FrameLayout implements
|
||||||
}
|
}
|
||||||
if (!mIsOpening) {
|
if (!mIsOpening) {
|
||||||
// When closing an app, we want the item on the workspace to be invisible immediately
|
// When closing an app, we want the item on the workspace to be invisible immediately
|
||||||
hideOriginalView(mOriginalIcon);
|
setIconAndDotVisible(mOriginalIcon, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,12 +541,7 @@ public class FloatingIconView extends FrameLayout implements
|
||||||
|
|
||||||
if (hideOriginal) {
|
if (hideOriginal) {
|
||||||
if (isOpening) {
|
if (isOpening) {
|
||||||
if (originalView instanceof BubbleTextView) {
|
setIconAndDotVisible(originalView, true);
|
||||||
((BubbleTextView) originalView).setIconVisible(true);
|
|
||||||
((BubbleTextView) originalView).setForceHideDot(false);
|
|
||||||
} else {
|
|
||||||
originalView.setVisibility(VISIBLE);
|
|
||||||
}
|
|
||||||
view.finish(dragLayer);
|
view.finish(dragLayer);
|
||||||
} else {
|
} else {
|
||||||
view.mFadeAnimatorSet = view.createFadeAnimation(originalView, dragLayer);
|
view.mFadeAnimatorSet = view.createFadeAnimation(originalView, dragLayer);
|
||||||
|
@ -615,12 +578,10 @@ public class FloatingIconView extends FrameLayout implements
|
||||||
});
|
});
|
||||||
|
|
||||||
if (originalView instanceof IconLabelDotView) {
|
if (originalView instanceof IconLabelDotView) {
|
||||||
IconLabelDotView view = (IconLabelDotView) originalView;
|
|
||||||
fade.addListener(new AnimatorListenerAdapter() {
|
fade.addListener(new AnimatorListenerAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationEnd(Animator animation) {
|
public void onAnimationEnd(Animator animation) {
|
||||||
view.setIconVisible(true);
|
setIconAndDotVisible(originalView, true);
|
||||||
view.setForceHideDot(false);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,24 @@
|
||||||
*/
|
*/
|
||||||
package com.android.launcher3.views;
|
package com.android.launcher3.views;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A view that has an icon, label, and notification dot.
|
* A view that has an icon, label, and notification dot.
|
||||||
*/
|
*/
|
||||||
public interface IconLabelDotView {
|
public interface IconLabelDotView {
|
||||||
void setIconVisible(boolean visible);
|
void setIconVisible(boolean visible);
|
||||||
void setForceHideDot(boolean hide);
|
void setForceHideDot(boolean hide);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the visibility of icon and dot of the view
|
||||||
|
*/
|
||||||
|
static void setIconAndDotVisible(View view, boolean visible) {
|
||||||
|
if (view instanceof IconLabelDotView) {
|
||||||
|
((IconLabelDotView) view).setIconVisible(visible);
|
||||||
|
((IconLabelDotView) view).setForceHideDot(!visible);
|
||||||
|
} else {
|
||||||
|
view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,7 +220,7 @@ public class OptionsPopupView extends ArrowPopup
|
||||||
if (!TextUtils.isEmpty(pickerPackage)) {
|
if (!TextUtils.isEmpty(pickerPackage)) {
|
||||||
intent.setPackage(pickerPackage);
|
intent.setPackage(pickerPackage);
|
||||||
}
|
}
|
||||||
return launcher.startActivitySafely(v, intent, dummyInfo(intent), null);
|
return launcher.startActivitySafely(v, intent, dummyInfo(intent));
|
||||||
}
|
}
|
||||||
|
|
||||||
static WorkspaceItemInfo dummyInfo(Intent intent) {
|
static WorkspaceItemInfo dummyInfo(Intent intent) {
|
||||||
|
|
|
@ -20,8 +20,10 @@ import android.util.Log;
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.icons.IconCache;
|
import com.android.launcher3.icons.IconCache;
|
||||||
import com.android.launcher3.model.data.PackageItemInfo;
|
import com.android.launcher3.model.data.PackageItemInfo;
|
||||||
|
import com.android.launcher3.testing.TestProtocol;
|
||||||
import com.android.launcher3.widget.WidgetsListAdapter.WidgetListRowEntryComparator;
|
import com.android.launcher3.widget.WidgetsListAdapter.WidgetListRowEntryComparator;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -32,8 +34,8 @@ import java.util.Iterator;
|
||||||
* methods accordingly.
|
* methods accordingly.
|
||||||
*/
|
*/
|
||||||
public class WidgetsDiffReporter {
|
public class WidgetsDiffReporter {
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = Utilities.IS_RUNNING_IN_TEST_HARNESS; // b/160238801
|
||||||
private static final String TAG = "WidgetsDiffReporter";
|
private static final String TAG = TestProtocol.NO_SCROLL_END_WIDGETS;
|
||||||
|
|
||||||
private final IconCache mIconCache;
|
private final IconCache mIconCache;
|
||||||
private final RecyclerView.Adapter mListener;
|
private final RecyclerView.Adapter mListener;
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.animation.PropertyValuesHolder;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
@ -38,8 +39,10 @@ import com.android.launcher3.Launcher;
|
||||||
import com.android.launcher3.LauncherAppState;
|
import com.android.launcher3.LauncherAppState;
|
||||||
import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
|
import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.anim.PendingAnimation;
|
import com.android.launcher3.anim.PendingAnimation;
|
||||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||||
|
import com.android.launcher3.testing.TestProtocol;
|
||||||
import com.android.launcher3.views.RecyclerViewFastScroller;
|
import com.android.launcher3.views.RecyclerViewFastScroller;
|
||||||
import com.android.launcher3.views.TopRoundedCornerView;
|
import com.android.launcher3.views.TopRoundedCornerView;
|
||||||
|
|
||||||
|
@ -68,6 +71,14 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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) {
|
public WidgetsFullSheet(Context context, AttributeSet attrs) {
|
||||||
this(context, attrs, 0);
|
this(context, attrs, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,9 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch
|
||||||
public int getCurrentScrollY() {
|
public int getCurrentScrollY() {
|
||||||
// Skip early if widgets are not bound.
|
// Skip early if widgets are not bound.
|
||||||
if (isModelNotReady() || getChildCount() == 0) {
|
if (isModelNotReady() || getChildCount() == 0) {
|
||||||
|
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||||
|
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "getCurrentScrollY: -1");
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,6 +131,10 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch
|
||||||
int y = (child.getMeasuredHeight() * rowIndex);
|
int y = (child.getMeasuredHeight() * rowIndex);
|
||||||
int offset = getLayoutManager().getDecoratedTop(child);
|
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;
|
return getPaddingTop() + y - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,13 +165,23 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch
|
||||||
mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset);
|
mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset);
|
||||||
}
|
}
|
||||||
if (mTouchDownOnScroller) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
|
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) {
|
if (mTouchDownOnScroller) {
|
||||||
mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
|
mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
|
||||||
}
|
}
|
||||||
|
@ -172,5 +189,31 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.systemui.plugins;
|
|
||||||
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.os.UserHandle;
|
|
||||||
|
|
||||||
import com.android.systemui.plugins.annotations.ProvidesInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Plugin interface which sends app launch events.
|
|
||||||
*/
|
|
||||||
@ProvidesInterface(action = AppLaunchEventsPlugin.ACTION, version = AppLaunchEventsPlugin.VERSION)
|
|
||||||
public interface AppLaunchEventsPlugin extends Plugin {
|
|
||||||
String ACTION = "com.android.systemui.action.PLUGIN_APP_EVENTS";
|
|
||||||
int VERSION = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receives onStartShortcut event from
|
|
||||||
* {@link com.android.launcher3.appprediction.PredictionAppTracker}.
|
|
||||||
*/
|
|
||||||
void onStartShortcut(String packageName, String shortcutId, UserHandle user, String container);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receives onStartApp event from
|
|
||||||
* {@link com.android.launcher3.appprediction.PredictionAppTracker}.
|
|
||||||
*/
|
|
||||||
void onStartApp(ComponentName componentName, UserHandle user, String container);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receives onDismissApp event from
|
|
||||||
* {@link com.android.launcher3.appprediction.PredictionAppTracker}.
|
|
||||||
*/
|
|
||||||
void onDismissApp(ComponentName componentName, UserHandle user, String container);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receives onReturnedToHome event from
|
|
||||||
* {@link com.android.launcher3.appprediction.PredictionAppTracker}.
|
|
||||||
*/
|
|
||||||
void onReturnedToHome();
|
|
||||||
}
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name="com.android.launcher3.testcomponent.AppWidgetNoConfig"
|
android:name="com.android.launcher3.testcomponent.AppWidgetNoConfig"
|
||||||
|
android:exported="true"
|
||||||
android:label="No Config">
|
android:label="No Config">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
|
||||||
|
@ -39,6 +40,7 @@
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name="com.android.launcher3.testcomponent.AppWdigetHidden"
|
android:name="com.android.launcher3.testcomponent.AppWdigetHidden"
|
||||||
|
android:exported="true"
|
||||||
android:label="Hidden widget">
|
android:label="Hidden widget">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
|
||||||
|
@ -49,6 +51,7 @@
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name="com.android.launcher3.testcomponent.AppWidgetWithConfig"
|
android:name="com.android.launcher3.testcomponent.AppWidgetWithConfig"
|
||||||
|
android:exported="true"
|
||||||
android:label="With Config">
|
android:label="With Config">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
|
||||||
|
@ -58,12 +61,14 @@
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.android.launcher3.testcomponent.WidgetConfigActivity">
|
android:name="com.android.launcher3.testcomponent.WidgetConfigActivity"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
|
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name="com.android.launcher3.testcomponent.CustomShortcutConfigActivity">
|
<activity android:name="com.android.launcher3.testcomponent.CustomShortcutConfigActivity"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.CREATE_SHORTCUT" />
|
<action android:name="android.intent.action.CREATE_SHORTCUT" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
@ -72,6 +77,7 @@
|
||||||
<activity
|
<activity
|
||||||
android:name="com.android.launcher3.testcomponent.RequestPinItemActivity"
|
android:name="com.android.launcher3.testcomponent.RequestPinItemActivity"
|
||||||
android:icon="@drawable/test_drawable_pin_item"
|
android:icon="@drawable/test_drawable_pin_item"
|
||||||
|
android:exported="true"
|
||||||
android:label="Test Pin Item">
|
android:label="Test Pin Item">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
@ -102,6 +108,7 @@
|
||||||
android:stateNotNeeded="true"
|
android:stateNotNeeded="true"
|
||||||
android:taskAffinity=""
|
android:taskAffinity=""
|
||||||
android:theme="@android:style/Theme.DeviceDefault.Light"
|
android:theme="@android:style/Theme.DeviceDefault.Light"
|
||||||
|
android:exported="true"
|
||||||
android:windowSoftInputMode="adjustPan">
|
android:windowSoftInputMode="adjustPan">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
@ -114,6 +121,7 @@
|
||||||
<activity
|
<activity
|
||||||
android:name="com.android.launcher3.testcomponent.BaseTestingActivity"
|
android:name="com.android.launcher3.testcomponent.BaseTestingActivity"
|
||||||
android:label="LauncherTestApp"
|
android:label="LauncherTestApp"
|
||||||
|
android:exported="true"
|
||||||
android:taskAffinity="com.android.launcher3.testcomponent.Affinity1">
|
android:taskAffinity="com.android.launcher3.testcomponent.Affinity1">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
@ -128,6 +136,7 @@
|
||||||
</activity>
|
</activity>
|
||||||
<activity-alias android:name="Activity2"
|
<activity-alias android:name="Activity2"
|
||||||
android:label="TestActivity2"
|
android:label="TestActivity2"
|
||||||
|
android:exported="true"
|
||||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
@ -136,6 +145,7 @@
|
||||||
</activity-alias>
|
</activity-alias>
|
||||||
<activity-alias android:name="Activity3"
|
<activity-alias android:name="Activity3"
|
||||||
android:label="TestActivity3"
|
android:label="TestActivity3"
|
||||||
|
android:exported="true"
|
||||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
@ -144,6 +154,7 @@
|
||||||
</activity-alias>
|
</activity-alias>
|
||||||
<activity-alias android:name="Activity4"
|
<activity-alias android:name="Activity4"
|
||||||
android:label="TestActivity4"
|
android:label="TestActivity4"
|
||||||
|
android:exported="true"
|
||||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
@ -152,6 +163,7 @@
|
||||||
</activity-alias>
|
</activity-alias>
|
||||||
<activity-alias android:name="Activity5"
|
<activity-alias android:name="Activity5"
|
||||||
android:label="TestActivity5"
|
android:label="TestActivity5"
|
||||||
|
android:exported="true"
|
||||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
@ -160,6 +172,7 @@
|
||||||
</activity-alias>
|
</activity-alias>
|
||||||
<activity-alias android:name="Activity6"
|
<activity-alias android:name="Activity6"
|
||||||
android:label="TestActivity6"
|
android:label="TestActivity6"
|
||||||
|
android:exported="true"
|
||||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
@ -168,6 +181,7 @@
|
||||||
</activity-alias>
|
</activity-alias>
|
||||||
<activity-alias android:name="Activity7"
|
<activity-alias android:name="Activity7"
|
||||||
android:label="TestActivity7"
|
android:label="TestActivity7"
|
||||||
|
android:exported="true"
|
||||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
@ -176,6 +190,7 @@
|
||||||
</activity-alias>
|
</activity-alias>
|
||||||
<activity-alias android:name="Activity8"
|
<activity-alias android:name="Activity8"
|
||||||
android:label="TestActivity8"
|
android:label="TestActivity8"
|
||||||
|
android:exported="true"
|
||||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
@ -184,6 +199,7 @@
|
||||||
</activity-alias>
|
</activity-alias>
|
||||||
<activity-alias android:name="Activity9"
|
<activity-alias android:name="Activity9"
|
||||||
android:label="TestActivity9"
|
android:label="TestActivity9"
|
||||||
|
android:exported="true"
|
||||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
@ -192,6 +208,7 @@
|
||||||
</activity-alias>
|
</activity-alias>
|
||||||
<activity-alias android:name="Activity10"
|
<activity-alias android:name="Activity10"
|
||||||
android:label="TestActivity10"
|
android:label="TestActivity10"
|
||||||
|
android:exported="true"
|
||||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
@ -200,6 +217,7 @@
|
||||||
</activity-alias>
|
</activity-alias>
|
||||||
<activity-alias android:name="Activity11"
|
<activity-alias android:name="Activity11"
|
||||||
android:label="TestActivity11"
|
android:label="TestActivity11"
|
||||||
|
android:exported="true"
|
||||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
<activity
|
<activity
|
||||||
android:name="Activity1"
|
android:name="Activity1"
|
||||||
android:icon="@mipmap/ic_launcher1"
|
android:icon="@mipmap/ic_launcher1"
|
||||||
|
android:exported="true"
|
||||||
android:label="Aardwolf">
|
android:label="Aardwolf">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
|
|
@ -73,20 +73,12 @@ public class ActivityLeakTracker implements Application.ActivityLifecycleCallbac
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean noLeakedActivities() {
|
public boolean noLeakedActivities() {
|
||||||
int liveActivities = 0;
|
|
||||||
int destroyedActivities = 0;
|
|
||||||
|
|
||||||
for (Activity activity : mActivities.keySet()) {
|
for (Activity activity : mActivities.keySet()) {
|
||||||
if (activity.isDestroyed()) {
|
if (activity.isDestroyed()) {
|
||||||
++destroyedActivities;
|
return false;
|
||||||
} else {
|
|
||||||
++liveActivities;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (liveActivities > 2) return false;
|
return mActivities.size() <= 2;
|
||||||
|
|
||||||
// It's OK to have 1 leaked activity if no active activities exist.
|
|
||||||
return liveActivities == 0 ? destroyedActivities <= 1 : destroyedActivities == 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,6 +152,7 @@ public final class LauncherInstrumentation {
|
||||||
private static final String WIDGETS_RES_ID = "widgets_list_view";
|
private static final String WIDGETS_RES_ID = "widgets_list_view";
|
||||||
private static final String CONTEXT_MENU_RES_ID = "deep_shortcuts_container";
|
private static final String CONTEXT_MENU_RES_ID = "deep_shortcuts_container";
|
||||||
public static final int WAIT_TIME_MS = 10000;
|
public static final int WAIT_TIME_MS = 10000;
|
||||||
|
public static final int LONG_WAIT_TIME_MS = 60000;
|
||||||
private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
|
private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
|
||||||
|
|
||||||
private static WeakReference<VisibleContainer> sActiveContainer = new WeakReference<>(null);
|
private static WeakReference<VisibleContainer> sActiveContainer = new WeakReference<>(null);
|
||||||
|
@ -635,9 +636,11 @@ public final class LauncherInstrumentation {
|
||||||
Parcelable executeAndWaitForEvent(Runnable command,
|
Parcelable executeAndWaitForEvent(Runnable command,
|
||||||
UiAutomation.AccessibilityEventFilter eventFilter, Supplier<String> message) {
|
UiAutomation.AccessibilityEventFilter eventFilter, Supplier<String> message) {
|
||||||
try {
|
try {
|
||||||
|
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "executeAndWaitForEvent: before");
|
||||||
final AccessibilityEvent event =
|
final AccessibilityEvent event =
|
||||||
mInstrumentation.getUiAutomation().executeAndWaitForEvent(
|
mInstrumentation.getUiAutomation().executeAndWaitForEvent(
|
||||||
command, eventFilter, WAIT_TIME_MS);
|
command, eventFilter, LONG_WAIT_TIME_MS);
|
||||||
|
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "executeAndWaitForEvent: after");
|
||||||
assertNotNull("executeAndWaitForEvent returned null (this can't happen)", event);
|
assertNotNull("executeAndWaitForEvent returned null (this can't happen)", event);
|
||||||
final Parcelable parcelableData = event.getParcelableData();
|
final Parcelable parcelableData = event.getParcelableData();
|
||||||
event.recycle();
|
event.recycle();
|
||||||
|
@ -1094,7 +1097,10 @@ public final class LauncherInstrumentation {
|
||||||
executeAndWaitForEvent(
|
executeAndWaitForEvent(
|
||||||
() -> linearGesture(
|
() -> linearGesture(
|
||||||
startX, startY, endX, endY, steps, slowDown, GestureScope.INSIDE),
|
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
|
() -> "Didn't receive a scroll end message: " + startX + ", " + startY
|
||||||
+ ", " + endX + ", " + endY);
|
+ ", " + endX + ", " + endY);
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue