Merge "Settle auto PiP transaction in WindowContainerTransaction" into sc-dev
diff --git a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
index 906071f..3f30d3e 100644
--- a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
+++ b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
@@ -19,11 +19,14 @@
import android.annotation.NonNull;
import android.content.ContentResolver;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
+import com.android.modules.annotation.MinSdk;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -77,6 +80,7 @@
There are four types of HDR video(Dolby-Vision, HDR10, HDR10+, HLG) supported by the platform,
application will only need to specify individual types they supported.
*/
+@MinSdk(Build.VERSION_CODES.S)
public final class ApplicationMediaCapabilities implements Parcelable {
private static final String TAG = "ApplicationMediaCapabilities";
diff --git a/apex/media/framework/java/android/media/MediaFeature.java b/apex/media/framework/java/android/media/MediaFeature.java
index 0e461888..8d1b159 100644
--- a/apex/media/framework/java/android/media/MediaFeature.java
+++ b/apex/media/framework/java/android/media/MediaFeature.java
@@ -17,6 +17,9 @@
package android.media;
import android.annotation.StringDef;
+import android.os.Build;
+
+import com.android.modules.annotation.MinSdk;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -24,6 +27,7 @@
/**
* MediaFeature defines various media features, e.g. hdr type.
*/
+@MinSdk(Build.VERSION_CODES.S)
public final class MediaFeature {
/**
* Defines tye type of HDR(high dynamic range) video.
diff --git a/apex/media/framework/java/android/media/MediaFrameworkInitializer.java b/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
index 9332835..de2924e 100644
--- a/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
+++ b/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
@@ -21,7 +21,9 @@
import android.annotation.SystemApi.Client;
import android.app.SystemServiceRegistry;
import android.content.Context;
+import android.os.Build;
+import com.android.modules.annotation.MinSdk;
import com.android.modules.utils.build.SdkLevel;
/**
@@ -29,6 +31,7 @@
*
* @hide
*/
+@MinSdk(Build.VERSION_CODES.S)
@SystemApi(client = Client.MODULE_LIBRARIES)
public class MediaFrameworkInitializer {
private MediaFrameworkInitializer() {
diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java
index 30d1896..84332e5 100644
--- a/apex/media/framework/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.net.Uri;
+import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
@@ -34,6 +35,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.annotation.MinSdk;
import java.io.FileNotFoundException;
import java.lang.annotation.Retention;
@@ -99,6 +101,7 @@
TODO(hkuang): Clarify whether supports framerate conversion.
@hide
*/
+@MinSdk(Build.VERSION_CODES.S)
@SystemApi
public final class MediaTranscodeManager {
private static final String TAG = "MediaTranscodeManager";
diff --git a/core/api/current.txt b/core/api/current.txt
index 63e35f1..bca2e92 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10961,6 +10961,7 @@
field public static final String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
field public static final String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
+ field public static final String ACTION_MANAGE_UNUSED_APPS = "android.intent.action.MANAGE_UNUSED_APPS";
field public static final String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
field public static final String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";
field public static final String ACTION_MEDIA_CHECKING = "android.intent.action.MEDIA_CHECKING";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5b61835..39e259d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5194,6 +5194,21 @@
field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int RADIO_TUNER = 1998; // 0x7ce
}
+ public final class MediaRouter2 {
+ method @NonNull public java.util.List<android.media.MediaRoute2Info> getAllRoutes();
+ method @Nullable public String getClientPackageName();
+ method @Nullable public android.media.MediaRouter2.RoutingController getController(@NonNull String);
+ method @Nullable public static android.media.MediaRouter2 getInstance(@NonNull android.content.Context, @NonNull String);
+ method public void setRouteVolume(@NonNull android.media.MediaRoute2Info, int);
+ method public void startScan();
+ method public void stopScan();
+ method public void transfer(@NonNull android.media.MediaRouter2.RoutingController, @NonNull android.media.MediaRoute2Info);
+ }
+
+ public abstract static class MediaRouter2.RouteCallback {
+ method public void onPreferredFeaturesChanged(@NonNull java.util.List<java.lang.String>);
+ }
+
public class PlayerProxy {
method public void pause();
method public void setPan(float);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c601aab..5cf83ac 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1901,6 +1901,20 @@
"android.intent.action.AUTO_REVOKE_PERMISSIONS";
/**
+ * Activity action: Launch UI to manage unused apps (hibernated apps).
+ *
+ * <p>
+ * Input: Nothing.
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_UNUSED_APPS =
+ "android.intent.action.MANAGE_UNUSED_APPS";
+
+ /**
* Activity action: Launch UI to review permissions for an app.
* The system uses this intent if permission review for apps not
* supporting the new runtime permissions model is enabled. In
diff --git a/core/java/android/service/timezone/TimeZoneProviderService.java b/core/java/android/service/timezone/TimeZoneProviderService.java
index d71a830..a9348c6 100644
--- a/core/java/android/service/timezone/TimeZoneProviderService.java
+++ b/core/java/android/service/timezone/TimeZoneProviderService.java
@@ -218,7 +218,30 @@
}
/**
- * Starts the provider sending updates.
+ * Informs the provider that it should start detecting and reporting the detected time zone
+ * state via the various {@code report} methods. Implementations of {@link
+ * #onStartUpdates(long)} should return immediately, and will typically be used to start
+ * worker threads or begin asynchronous location listening.
+ *
+ * <p>Between {@link #onStartUpdates(long)} and {@link #onStopUpdates()} calls, the Android
+ * system server holds the latest report from the provider in memory. After an initial report,
+ * provider implementations are only required to send a report via {@link
+ * #reportSuggestion(TimeZoneProviderSuggestion)} or via {@link #reportUncertain()} when it
+ * differs from the previous report.
+ *
+ * <p>{@link #reportPermanentFailure(Throwable)} can also be called by provider implementations
+ * in rare cases, after which the provider should consider itself stopped and not make any
+ * further reports. {@link #onStopUpdates()} will not be called in this case.
+ *
+ * <p>The {@code initializationTimeoutMillis} parameter indicates how long the provider has been
+ * granted to call one of the {@code report} methods for the first time. If the provider does
+ * not call one of the {@code report} methods in this time, it may be judged uncertain and the
+ * Android system server may move on to use other providers or detection methods. Providers
+ * should therefore make best efforts during this time to generate a report, which could involve
+ * increased power usage. Providers should preferably report an explicit {@link
+ * #reportUncertain()} if the time zone(s) cannot be detected within the initialization timeout.
+ *
+ * @see #onStopUpdates() for the signal from the system server to stop sending reports
*/
public abstract void onStartUpdates(@DurationMillisLong long initializationTimeoutMillis);
@@ -228,7 +251,8 @@
}
/**
- * Stops the provider sending updates.
+ * Stops the provider sending further updates. This will be called after {@link
+ * #onStartUpdates(long)}.
*/
public abstract void onStopUpdates();
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index ee98878..52801fa 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -474,6 +474,12 @@
public static final String SHARE_USE_SERVICE_TARGETS = "share_use_service_targets";
+ /*
+ * (long) The duration that the home button must be pressed before triggering Assist
+ */
+ public static final String HOME_BUTTON_LONG_PRESS_DURATION_MS =
+ "home_button_long_press_duration_ms";
+
private SystemUiDeviceConfigFlags() {
}
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f9227617..d783b44 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2775,11 +2775,11 @@
The app can check whether it has this authorization by calling
{@link android.provider.Settings#canDrawOverlays
Settings.canDrawOverlays()}.
- <p>Protection level: signature|appop|installer|appPredictor|pre23|development -->
+ <p>Protection level: signature|setup|appop|installer|appPredictor|pre23|development -->
<permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
android:label="@string/permlab_systemAlertWindow"
android:description="@string/permdesc_systemAlertWindow"
- android:protectionLevel="signature|appop|installer|appPredictor|pre23|development" />
+ android:protectionLevel="signature|setup|appop|installer|appPredictor|pre23|development" />
<!-- @SystemApi @hide Allows an application to create windows using the type
{@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY},
diff --git a/core/tests/mockingcoretests/src/android/view/DisplayTests.java b/core/tests/mockingcoretests/src/android/view/DisplayTest.java
similarity index 98%
rename from core/tests/mockingcoretests/src/android/view/DisplayTests.java
rename to core/tests/mockingcoretests/src/android/view/DisplayTest.java
index a036db2..f8dd153 100644
--- a/core/tests/mockingcoretests/src/android/view/DisplayTests.java
+++ b/core/tests/mockingcoretests/src/android/view/DisplayTest.java
@@ -56,12 +56,15 @@
*
* <p>Build/Install/Run:
*
- * atest FrameworksMockingCoreTests:android.view.DisplayTests
+ * atest FrameworksMockingCoreTests:android.view.DisplayTest
+ *
+ * <p>This test class is a part of Window Manager Service tests and specified in
+ * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
@Presubmit
-public class DisplayTests {
+public class DisplayTest {
private static final int APP_WIDTH = 272;
private static final int APP_HEIGHT = 700;
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index b3a180d..b171599 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -155,6 +155,7 @@
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="media" />
<assign-permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" uid="media" />
<assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="media" />
+ <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="media" />
<assign-permission name="android.permission.INTERNET" uid="media" />
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 3f03302..1b5dc8b 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -38,14 +38,6 @@
path: "src",
}
-filegroup {
- name: "wm_shell-aidls",
- srcs: [
- "src/**/*.aidl",
- ],
- path: "src",
-}
-
// TODO(b/168581922) protologtool do not support kotlin(*.kt)
filegroup {
name: "wm_shell-sources-kt",
@@ -106,7 +98,7 @@
":wm_shell_protolog_src",
// TODO(b/168581922) protologtool do not support kotlin(*.kt)
":wm_shell-sources-kt",
- ":wm_shell-aidls",
+ "src/**/I*.aidl",
],
resource_dirs: [
"res",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
index d451f4a..eaed24d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
@@ -47,7 +47,21 @@
private final ShellExecutor mMainExecutor;
private final HandlerImpl mImpl = new HandlerImpl();
- public ShellCommandHandlerImpl(
+ public static ShellCommandHandler create(
+ ShellTaskOrganizer shellTaskOrganizer,
+ Optional<LegacySplitScreenController> legacySplitScreenOptional,
+ Optional<SplitScreenController> splitScreenOptional,
+ Optional<Pip> pipOptional,
+ Optional<OneHandedController> oneHandedOptional,
+ Optional<HideDisplayCutoutController> hideDisplayCutout,
+ Optional<AppPairsController> appPairsOptional,
+ ShellExecutor mainExecutor) {
+ return new ShellCommandHandlerImpl(shellTaskOrganizer, legacySplitScreenOptional,
+ splitScreenOptional, pipOptional, oneHandedOptional, hideDisplayCutout,
+ appPairsOptional, mainExecutor).mImpl;
+ }
+
+ private ShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
@@ -66,10 +80,6 @@
mMainExecutor = mainExecutor;
}
- public ShellCommandHandler asShellCommandHandler() {
- return mImpl;
- }
-
/** Dumps WM Shell internal state. */
private void dump(PrintWriter pw) {
mShellTaskOrganizer.dump(pw, "");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index 6f4550c..85bd24c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -26,7 +26,7 @@
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.splitscreen.SplitScreenController;
-import com.android.wm.shell.startingsurface.StartingWindowController;
+import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -47,20 +47,44 @@
private final FullscreenTaskListener mFullscreenTaskListener;
private final ShellExecutor mMainExecutor;
private final Transitions mTransitions;
- private final StartingWindowController mStartingWindow;
+ private final Optional<StartingSurface> mStartingSurfaceOptional;
private final InitImpl mImpl = new InitImpl();
- public ShellInitImpl(DisplayImeController displayImeController,
+ public static ShellInit create(DisplayImeController displayImeController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
+ Optional<StartingSurface> startingSurfaceOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
- StartingWindowController startingWindow,
+ ShellExecutor mainExecutor) {
+ return new ShellInitImpl(displayImeController,
+ dragAndDropController,
+ shellTaskOrganizer,
+ legacySplitScreenOptional,
+ splitScreenOptional,
+ appPairsOptional,
+ startingSurfaceOptional,
+ pipTouchHandlerOptional,
+ fullscreenTaskListener,
+ transitions,
+ mainExecutor).mImpl;
+ }
+
+ private ShellInitImpl(DisplayImeController displayImeController,
+ DragAndDropController dragAndDropController,
+ ShellTaskOrganizer shellTaskOrganizer,
+ Optional<LegacySplitScreenController> legacySplitScreenOptional,
+ Optional<SplitScreenController> splitScreenOptional,
+ Optional<AppPairsController> appPairsOptional,
+ Optional<StartingSurface> startingSurfaceOptional,
+ Optional<PipTouchHandler> pipTouchHandlerOptional,
+ FullscreenTaskListener fullscreenTaskListener,
+ Transitions transitions,
ShellExecutor mainExecutor) {
mDisplayImeController = displayImeController;
mDragAndDropController = dragAndDropController;
@@ -72,21 +96,17 @@
mPipTouchHandlerOptional = pipTouchHandlerOptional;
mTransitions = transitions;
mMainExecutor = mainExecutor;
- mStartingWindow = startingWindow;
- }
-
- public ShellInit asShellInit() {
- return mImpl;
+ mStartingSurfaceOptional = startingSurfaceOptional;
}
private void init() {
// Start listening for display changes
mDisplayImeController.startMonitorDisplays();
- // Setup the shell organizer
mShellTaskOrganizer.addListenerForType(
mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN);
- mShellTaskOrganizer.initStartingWindow(mStartingWindow);
+ mStartingSurfaceOptional.ifPresent(mShellTaskOrganizer::initStartingSurface);
+ // Register the shell organizer
mShellTaskOrganizer.registerOrganizer();
mAppPairsOptional.ifPresent(AppPairsController::onOrganizerRegistered);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 94d13ea..fcb53cd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -48,7 +48,7 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
-import com.android.wm.shell.startingsurface.StartingWindowController;
+import com.android.wm.shell.startingsurface.StartingSurface;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -133,7 +133,7 @@
private final ArraySet<LocusIdListener> mLocusIdListeners = new ArraySet<>();
private final Object mLock = new Object();
- private StartingWindowController mStartingWindow;
+ private StartingSurface mStartingSurface;
/**
* In charge of showing size compat UI. Can be {@code null} if device doesn't support size
@@ -184,8 +184,8 @@
/**
* @hide
*/
- public void initStartingWindow(StartingWindowController startingWindow) {
- mStartingWindow = startingWindow;
+ public void initStartingSurface(StartingSurface startingSurface) {
+ mStartingSurface = startingSurface;
}
/**
@@ -302,23 +302,23 @@
@Override
public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
- if (mStartingWindow != null) {
- mStartingWindow.addStartingWindow(info, appToken);
+ if (mStartingSurface != null) {
+ mStartingSurface.addStartingWindow(info, appToken);
}
}
@Override
public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
boolean playRevealAnimation) {
- if (mStartingWindow != null) {
- mStartingWindow.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
+ if (mStartingSurface != null) {
+ mStartingSurface.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
}
}
@Override
public void copySplashScreenView(int taskId) {
- if (mStartingWindow != null) {
- mStartingWindow.copySplashScreenView(taskId);
+ if (mStartingSurface != null) {
+ mStartingSurface.copySplashScreenView(taskId);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java
deleted file mode 100644
index b29058b..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2021 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.wm.shell.common;
-
-import android.Manifest;
-import android.util.Slog;
-
-import java.util.function.Consumer;
-
-/**
- * Helpers for working with executors
- */
-public class ExecutorUtils {
-
- /**
- * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given
- * callback.
- */
- public static <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance,
- String log, Consumer<T> callback) {
- executeRemoteCallWithTaskPermission(controllerInstance, log, callback,
- false /* blocking */);
- }
-
- /**
- * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given
- * callback.
- */
- public static <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance,
- String log, Consumer<T> callback, boolean blocking) {
- if (controllerInstance == null) return;
-
- final RemoteCallable<T> controller = controllerInstance;
- controllerInstance.getContext().enforceCallingPermission(
- Manifest.permission.MANAGE_ACTIVITY_TASKS, log);
- if (blocking) {
- try {
- controllerInstance.getRemoteCallExecutor().executeBlocking(() -> {
- callback.accept((T) controller);
- });
- } catch (InterruptedException e) {
- Slog.e("ExecutorUtils", "Remote call failed", e);
- }
- } else {
- controllerInstance.getRemoteCallExecutor().execute(() -> {
- callback.accept((T) controller);
- });
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java
deleted file mode 100644
index 30f535b..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2021 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.wm.shell.common;
-
-import android.content.Context;
-
-/**
- * An interface for controllers that can receive remote calls.
- */
-public interface RemoteCallable<T> {
- /**
- * Returns a context used for permission checking.
- */
- Context getContext();
-
- /**
- * Returns the executor to post the handler callback to.
- */
- ShellExecutor getRemoteCallExecutor();
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 9a09ca4..aab2334 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -235,7 +235,7 @@
mStarter.startShortcut(packageName, id, stage, position, opts, user);
} else {
mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT),
- null, stage, position, opts);
+ mContext, null, stage, position, opts);
}
}
@@ -295,7 +295,7 @@
@Nullable Bundle options);
void startShortcut(String packageName, String shortcutId, @StageType int stage,
@StagePosition int position, @Nullable Bundle options, UserHandle user);
- void startIntent(PendingIntent intent, Intent fillInIntent,
+ void startIntent(PendingIntent intent, Context context, Intent fillInIntent,
@StageType int stage, @StagePosition int position,
@Nullable Bundle options);
void enterSplitScreen(int taskId, boolean leftOrTop);
@@ -337,8 +337,9 @@
}
@Override
- public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent, int stage,
- int position, @Nullable Bundle options) {
+ public void startIntent(PendingIntent intent, Context context,
+ @Nullable Intent fillInIntent, int stage, int position,
+ @Nullable Bundle options) {
try {
intent.send(mContext, 0, fillInIntent, null, null, null, options);
} catch (PendingIntent.CanceledException e) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/IOneHanded.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/IOneHanded.aidl
deleted file mode 100644
index 008b508..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/IOneHanded.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2021 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.wm.shell.onehanded;
-
-/**
- * Interface that is exposed to remote callers to manipulate the OneHanded feature.
- */
-interface IOneHanded {
-
- /**
- * Enters one handed mode.
- */
- oneway void startOneHanded() = 1;
-
- /**
- * Exits one handed mode.
- */
- oneway void stopOneHanded() = 2;
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
index a7e9a01..4f31c37 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
@@ -26,14 +26,6 @@
*/
@ExternalThread
public interface OneHanded {
-
- /**
- * Returns a binder that can be passed to an external process to manipulate OneHanded.
- */
- default IOneHanded createExternalInterface() {
- return null;
- }
-
/**
* Return one handed settings enabled or not.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 8022c1b..5fc7c98 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -18,10 +18,6 @@
import static android.os.UserHandle.USER_CURRENT;
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
-
-import android.Manifest;
-import android.annotation.BinderThread;
import android.content.ComponentName;
import android.content.Context;
import android.content.om.IOverlayManager;
@@ -47,8 +43,6 @@
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.ExecutorUtils;
-import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -60,7 +54,7 @@
/**
* Manages and manipulates the one handed states, transitions, and gesture for phones.
*/
-public class OneHandedController implements RemoteCallable<OneHandedController> {
+public class OneHandedController {
private static final String TAG = "OneHandedController";
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
@@ -245,16 +239,6 @@
return mImpl;
}
- @Override
- public Context getContext() {
- return mContext;
- }
-
- @Override
- public ShellExecutor getRemoteCallExecutor() {
- return mMainExecutor;
- }
-
/**
* Set one handed enabled or disabled when user update settings
*/
@@ -583,22 +567,8 @@
}
}
- /**
- * The interface for calls from outside the Shell, within the host process.
- */
@ExternalThread
private class OneHandedImpl implements OneHanded {
- private IOneHandedImpl mIOneHanded;
-
- @Override
- public IOneHanded createExternalInterface() {
- if (mIOneHanded != null) {
- mIOneHanded.invalidate();
- }
- mIOneHanded = new IOneHandedImpl(OneHandedController.this);
- return mIOneHanded;
- }
-
@Override
public boolean isOneHandedEnabled() {
// This is volatile so return directly
@@ -667,39 +637,4 @@
});
}
}
-
- /**
- * The interface for calls from outside the host process.
- */
- @BinderThread
- private static class IOneHandedImpl extends IOneHanded.Stub {
- private OneHandedController mController;
-
- IOneHandedImpl(OneHandedController controller) {
- mController = controller;
- }
-
- /**
- * Invalidates this instance, preventing future calls from updating the controller.
- */
- void invalidate() {
- mController = null;
- }
-
- @Override
- public void startOneHanded() {
- executeRemoteCallWithTaskPermission(mController, "startOneHanded",
- (controller) -> {
- controller.startOneHanded();
- });
- }
-
- @Override
- public void stopOneHanded() {
- executeRemoteCallWithTaskPermission(mController, "stopOneHanded",
- (controller) -> {
- controller.stopOneHanded();
- });
- }
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
deleted file mode 100644
index a6ffa6e..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2021 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.wm.shell.pip;
-
-import android.app.PictureInPictureParams;
-import android.content.ComponentName;
-import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
-
-import com.android.wm.shell.pip.IPipAnimationListener;
-
-/**
- * Interface that is exposed to remote callers to manipulate the Pip feature.
- */
-interface IPip {
-
- /**
- * Notifies that Activity is about to be swiped to home with entering PiP transition and
- * queries the destination bounds for PiP depends on Launcher's rotation and shelf height.
- *
- * @param componentName ComponentName represents the Activity
- * @param activityInfo ActivityInfo tied to the Activity
- * @param pictureInPictureParams PictureInPictureParams tied to the Activity
- * @param launcherRotation Launcher rotation to calculate the PiP destination bounds
- * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds
- * @return destination bounds the PiP window should land into
- */
- Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo,
- in PictureInPictureParams pictureInPictureParams,
- int launcherRotation, int shelfHeight) = 1;
-
- /**
- * Notifies the swiping Activity to PiP onto home transition is finished
- *
- * @param componentName ComponentName represents the Activity
- * @param destinationBounds the destination bounds the PiP window lands into
- */
- oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 2;
-
- /**
- * Sets listener to get pinned stack animation callbacks.
- */
- oneway void setPinnedStackAnimationListener(IPipAnimationListener listener) = 3;
-
- /**
- * Sets the shelf height and visibility.
- */
- oneway void setShelfHeight(boolean visible, int shelfHeight) = 4;
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index 6d4773b..d14c3e3c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -16,10 +16,15 @@
package com.android.wm.shell.pip;
+import android.annotation.Nullable;
+import android.app.PictureInPictureParams;
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import com.android.wm.shell.common.annotations.ExternalThread;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -29,14 +34,6 @@
*/
@ExternalThread
public interface Pip {
-
- /**
- * Returns a binder that can be passed to an external process to manipulate PIP.
- */
- default IPip createExternalInterface() {
- return null;
- }
-
/**
* Expand PIP, it's possible that specific request to activate the window via Alt-tab.
*/
@@ -112,6 +109,30 @@
default void showPictureInPictureMenu() {}
/**
+ * Called by Launcher when swiping an auto-pip enabled Activity to home starts
+ * @param componentName {@link ComponentName} represents the Activity entering PiP
+ * @param activityInfo {@link ActivityInfo} tied to the Activity
+ * @param pictureInPictureParams {@link PictureInPictureParams} tied to the Activity
+ * @param launcherRotation Rotation Launcher is in
+ * @param shelfHeight Shelf height when landing PiP window onto Launcher
+ * @return Destination bounds of PiP window based on the parameters passed in
+ */
+ default Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
+ PictureInPictureParams pictureInPictureParams,
+ int launcherRotation, int shelfHeight) {
+ return null;
+ }
+
+ /**
+ * Called by Launcher when swiping an auto-pip enable Activity to home finishes
+ * @param componentName {@link ComponentName} represents the Activity entering PiP
+ * @param destinationBounds Destination bounds of PiP window
+ */
+ default void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+ return;
+ }
+
+ /**
* Called by NavigationBar in order to listen in for PiP bounds change. This is mostly used
* for times where the PiP bounds could conflict with SystemUI elements, such as a stashed
* PiP and the Back-from-Edge gesture.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 501b90e..9a584c6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -21,10 +21,8 @@
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.view.WindowManager.INPUT_CONSUMER_PIP;
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
-import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.PictureInPictureParams;
@@ -35,7 +33,6 @@
import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -47,7 +44,6 @@
import android.view.WindowManagerGlobal;
import android.window.WindowContainerTransaction;
-import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -55,13 +51,9 @@
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.ExecutorUtils;
-import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
-import com.android.wm.shell.pip.IPip;
-import com.android.wm.shell.pip.IPipAnimationListener;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
@@ -79,8 +71,7 @@
/**
* Manages the picture-in-picture (PIP) UI and states for Phones.
*/
-public class PipController implements PipTransitionController.PipTransitionCallback,
- RemoteCallable<PipController> {
+public class PipController implements PipTransitionController.PipTransitionCallback {
private static final String TAG = "PipController";
private Context mContext;
@@ -94,12 +85,12 @@
private PipBoundsState mPipBoundsState;
private PipTouchHandler mTouchHandler;
private PipTransitionController mPipTransitionController;
- protected final PipImpl mImpl;
+ protected final PipImpl mImpl = new PipImpl();
private final Rect mTmpInsetBounds = new Rect();
private boolean mIsInFixedRotation;
- private IPipAnimationListener mPinnedStackAnimationRecentsCallback;
+ private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
protected PhonePipMenuController mMenuController;
protected PipTaskOrganizer mPipTaskOrganizer;
@@ -273,7 +264,6 @@
}
mContext = context;
- mImpl = new PipImpl();
mWindowManagerShellWrapper = windowManagerShellWrapper;
mDisplayController = displayController;
mPipBoundsAlgorithm = pipBoundsAlgorithm;
@@ -376,16 +366,6 @@
});
}
- @Override
- public Context getContext() {
- return mContext;
- }
-
- @Override
- public ShellExecutor getRemoteCallExecutor() {
- return mMainExecutor;
- }
-
private void onConfigurationChanged(Configuration newConfig) {
mPipBoundsAlgorithm.onConfigurationChanged(mContext);
mTouchHandler.onConfigurationChanged();
@@ -494,7 +474,7 @@
mPipTaskOrganizer.setOneShotAnimationType(animationType);
}
- private void setPinnedStackAnimationListener(IPipAnimationListener callback) {
+ private void setPinnedStackAnimationListener(Consumer<Boolean> callback) {
mPinnedStackAnimationRecentsCallback = callback;
}
@@ -532,11 +512,7 @@
// Disable touches while the animation is running
mTouchHandler.setTouchEnabled(false);
if (mPinnedStackAnimationRecentsCallback != null) {
- try {
- mPinnedStackAnimationRecentsCallback.onPipAnimationStarted();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to call onPinnedStackAnimationStarted()", e);
- }
+ mPinnedStackAnimationRecentsCallback.accept(true);
}
}
@@ -662,21 +638,7 @@
mPipInputConsumer.dump(pw, innerPrefix);
}
- /**
- * The interface for calls from outside the Shell, within the host process.
- */
private class PipImpl implements Pip {
- private IPipImpl mIPip;
-
- @Override
- public IPip createExternalInterface() {
- if (mIPip != null) {
- mIPip.invalidate();
- }
- mIPip = new IPipImpl(PipController.this);
- return mIPip;
- }
-
@Override
public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
mMainExecutor.execute(() -> {
@@ -734,6 +696,13 @@
}
@Override
+ public void setPinnedStackAnimationListener(Consumer<Boolean> callback) {
+ mMainExecutor.execute(() -> {
+ PipController.this.setPinnedStackAnimationListener(callback);
+ });
+ }
+
+ @Override
public void setPinnedStackAnimationType(int animationType) {
mMainExecutor.execute(() -> {
PipController.this.setPinnedStackAnimationType(animationType);
@@ -755,6 +724,29 @@
}
@Override
+ public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
+ PictureInPictureParams pictureInPictureParams, int launcherRotation,
+ int shelfHeight) {
+ Rect[] result = new Rect[1];
+ try {
+ mMainExecutor.executeBlocking(() -> {
+ result[0] = PipController.this.startSwipePipToHome(componentName, activityInfo,
+ pictureInPictureParams, launcherRotation, shelfHeight);
+ });
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Failed to start swipe pip to home");
+ }
+ return result[0];
+ }
+
+ @Override
+ public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+ mMainExecutor.execute(() -> {
+ PipController.this.stopSwipePipToHome(componentName, destinationBounds);
+ });
+ }
+
+ @Override
public void dump(PrintWriter pw) {
try {
mMainExecutor.executeBlocking(() -> {
@@ -765,89 +757,4 @@
}
}
}
-
- /**
- * The interface for calls from outside the host process.
- */
- @BinderThread
- private static class IPipImpl extends IPip.Stub {
- private PipController mController;
- private IPipAnimationListener mListener;
- private final IBinder.DeathRecipient mListenerDeathRecipient =
- new IBinder.DeathRecipient() {
- @Override
- @BinderThread
- public void binderDied() {
- final PipController controller = mController;
- controller.getRemoteCallExecutor().execute(() -> {
- mListener = null;
- controller.setPinnedStackAnimationListener(null);
- });
- }
- };
-
- IPipImpl(PipController controller) {
- mController = controller;
- }
-
- /**
- * Invalidates this instance, preventing future calls from updating the controller.
- */
- void invalidate() {
- mController = null;
- }
-
- @Override
- public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
- PictureInPictureParams pictureInPictureParams, int launcherRotation,
- int shelfHeight) {
- Rect[] result = new Rect[1];
- executeRemoteCallWithTaskPermission(mController, "startSwipePipToHome",
- (controller) -> {
- result[0] = controller.startSwipePipToHome(componentName, activityInfo,
- pictureInPictureParams, launcherRotation, shelfHeight);
- }, true /* blocking */);
- return result[0];
- }
-
- @Override
- public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
- executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome",
- (controller) -> {
- controller.stopSwipePipToHome(componentName, destinationBounds);
- });
- }
-
- @Override
- public void setShelfHeight(boolean visible, int height) {
- executeRemoteCallWithTaskPermission(mController, "setShelfHeight",
- (controller) -> {
- controller.setShelfHeight(visible, height);
- });
- }
-
- @Override
- public void setPinnedStackAnimationListener(IPipAnimationListener listener) {
- executeRemoteCallWithTaskPermission(mController, "setPinnedStackAnimationListener",
- (controller) -> {
- if (mListener != null) {
- // Reset the old death recipient
- mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- }
- if (listener != null) {
- // Register the death recipient for the new listener to clear the listener
- try {
- listener.asBinder().linkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to link to death");
- return;
- }
- }
- mListener = listener;
- controller.setPinnedStackAnimationListener(listener);
- });
- }
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
deleted file mode 100644
index 0c46eab..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2021 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.wm.shell.splitscreen;
-
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.UserHandle;
-
-import com.android.wm.shell.splitscreen.ISplitScreenListener;
-
-/**
- * Interface that is exposed to remote callers to manipulate the splitscreen feature.
- */
-interface ISplitScreen {
-
- /**
- * Registers a split screen listener.
- */
- oneway void registerSplitScreenListener(in ISplitScreenListener listener) = 1;
-
- /**
- * Unregisters a split screen listener.
- */
- oneway void unregisterSplitScreenListener(in ISplitScreenListener listener) = 2;
-
- /**
- * Hides the side-stage if it is currently visible.
- */
- oneway void setSideStageVisibility(boolean visible) = 3;
-
- /**
- * Removes a task from the side stage.
- */
- oneway void removeFromSideStage(int taskId) = 4;
-
- /**
- * Removes the split-screen stages.
- */
- oneway void exitSplitScreen() = 5;
-
- /**
- * @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible.
- */
- oneway void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) = 6;
-
- /**
- * Starts a task in a stage.
- */
- oneway void startTask(int taskId, int stage, int position, in Bundle options) = 7;
-
- /**
- * Starts a shortcut in a stage.
- */
- oneway void startShortcut(String packageName, String shortcutId, int stage, int position,
- in Bundle options, in UserHandle user) = 8;
-
- /**
- * Starts an activity in a stage.
- */
- oneway void startIntent(in PendingIntent intent, in Intent fillInIntent, int stage,
- int position, in Bundle options) = 9;
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 340b55d7..25a84bd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -35,7 +35,7 @@
* TODO: Figure out which of these are actually needed outside of the Shell
*/
@ExternalThread
-public interface SplitScreen {
+public interface SplitScreen extends DragAndDropPolicy.Starter {
/**
* Stage position isn't specified normally meaning to use what ever it is currently set to.
*/
@@ -89,10 +89,35 @@
void onTaskStageChanged(int taskId, @StageType int stage, boolean visible);
}
- /**
- * Returns a binder that can be passed to an external process to manipulate SplitScreen.
- */
- default ISplitScreen createExternalInterface() {
- return null;
- }
+ /** @return {@code true} if split-screen is currently visible. */
+ boolean isSplitScreenVisible();
+ /** Moves a task in the side-stage of split-screen. */
+ boolean moveToSideStage(int taskId, @StagePosition int sideStagePosition);
+ /** Moves a task in the side-stage of split-screen. */
+ boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
+ @StagePosition int sideStagePosition);
+ /** Removes a task from the side-stage of split-screen. */
+ boolean removeFromSideStage(int taskId);
+ /** Sets the position of the side-stage. */
+ void setSideStagePosition(@StagePosition int sideStagePosition);
+ /** Hides the side-stage if it is currently visible. */
+ void setSideStageVisibility(boolean visible);
+
+ /** Removes the split-screen stages. */
+ void exitSplitScreen();
+ /** @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible. */
+ void exitSplitScreenOnHide(boolean exitSplitScreenOnHide);
+ /** Gets the stage bounds. */
+ void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds);
+
+ void registerSplitScreenListener(SplitScreenListener listener);
+ void unregisterSplitScreenListener(SplitScreenListener listener);
+
+ void startTask(int taskId,
+ @StageType int stage, @StagePosition int position, @Nullable Bundle options);
+ void startShortcut(String packageName, String shortcutId, @StageType int stage,
+ @StagePosition int position, @Nullable Bundle options, UserHandle user);
+ void startIntent(PendingIntent intent, Context context,
+ @Nullable Intent fillInIntent, @StageType int stage,
+ @StagePosition int position, @Nullable Bundle options);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index d4362ef..bb6f6f2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -18,7 +18,6 @@
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED;
@@ -35,24 +34,19 @@
import android.content.pm.LauncherApps;
import android.graphics.Rect;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;
-import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
-import com.android.wm.shell.splitscreen.ISplitScreenListener;
import java.io.PrintWriter;
@@ -61,8 +55,7 @@
* {@link SplitScreen}.
* @see StageCoordinator
*/
-public class SplitScreenController implements DragAndDropPolicy.Starter,
- RemoteCallable<SplitScreenController> {
+public class SplitScreenController implements DragAndDropPolicy.Starter {
private static final String TAG = SplitScreenController.class.getSimpleName();
private final ShellTaskOrganizer mTaskOrganizer;
@@ -91,16 +84,6 @@
return mImpl;
}
- @Override
- public Context getContext() {
- return mContext;
- }
-
- @Override
- public ShellExecutor getRemoteCallExecutor() {
- return mMainExecutor;
- }
-
public void onOrganizerRegistered() {
if (mStageCoordinator == null) {
// TODO: Multi-display
@@ -189,13 +172,13 @@
}
}
- public void startIntent(PendingIntent intent, Intent fillInIntent,
- @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
- @Nullable Bundle options) {
+ public void startIntent(PendingIntent intent, Context context,
+ Intent fillInIntent, @SplitScreen.StageType int stage,
+ @SplitScreen.StagePosition int position, @Nullable Bundle options) {
options = resolveStartStage(stage, position, options);
try {
- intent.send(mContext, 0, fillInIntent, null, null, null, options);
+ intent.send(context, 0, fillInIntent, null, null, null, options);
} catch (PendingIntent.CanceledException e) {
Slog.e(TAG, "Failed to launch activity", e);
}
@@ -259,170 +242,121 @@
}
}
- /**
- * The interface for calls from outside the Shell, within the host process.
- */
- @ExternalThread
private class SplitScreenImpl implements SplitScreen {
- private ISplitScreenImpl mISplitScreen;
-
@Override
- public ISplitScreen createExternalInterface() {
- if (mISplitScreen != null) {
- mISplitScreen.invalidate();
- }
- mISplitScreen = new ISplitScreenImpl(SplitScreenController.this);
- return mISplitScreen;
- }
- }
-
- /**
- * The interface for calls from outside the host process.
- */
- @BinderThread
- private static class ISplitScreenImpl extends ISplitScreen.Stub {
- private SplitScreenController mController;
- private ISplitScreenListener mListener;
- private final SplitScreen.SplitScreenListener mSplitScreenListener =
- new SplitScreen.SplitScreenListener() {
- @Override
- public void onStagePositionChanged(int stage, int position) {
- try {
- if (mListener != null) {
- mListener.onStagePositionChanged(stage, position);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "onStagePositionChanged", e);
- }
- }
-
- @Override
- public void onTaskStageChanged(int taskId, int stage, boolean visible) {
- try {
- if (mListener != null) {
- mListener.onTaskStageChanged(taskId, stage, visible);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "onTaskStageChanged", e);
- }
- }
- };
- private final IBinder.DeathRecipient mListenerDeathRecipient =
- new IBinder.DeathRecipient() {
- @Override
- @BinderThread
- public void binderDied() {
- final SplitScreenController controller = mController;
- controller.getRemoteCallExecutor().execute(() -> {
- mListener = null;
- controller.unregisterSplitScreenListener(mSplitScreenListener);
- });
- }
- };
-
- public ISplitScreenImpl(SplitScreenController controller) {
- mController = controller;
- }
-
- /**
- * Invalidates this instance, preventing future calls from updating the controller.
- */
- void invalidate() {
- mController = null;
+ public boolean isSplitScreenVisible() {
+ return mMainExecutor.executeBlockingForResult(() -> {
+ return SplitScreenController.this.isSplitScreenVisible();
+ }, Boolean.class);
}
@Override
- public void registerSplitScreenListener(ISplitScreenListener listener) {
- executeRemoteCallWithTaskPermission(mController, "registerSplitScreenListener",
- (controller) -> {
- if (mListener != null) {
- mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- }
- if (listener != null) {
- try {
- listener.asBinder().linkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to link to death");
- return;
- }
- }
- mListener = listener;
- controller.registerSplitScreenListener(mSplitScreenListener);
- });
+ public boolean moveToSideStage(int taskId, int sideStagePosition) {
+ return mMainExecutor.executeBlockingForResult(() -> {
+ return SplitScreenController.this.moveToSideStage(taskId, sideStagePosition);
+ }, Boolean.class);
}
@Override
- public void unregisterSplitScreenListener(ISplitScreenListener listener) {
- executeRemoteCallWithTaskPermission(mController, "unregisterSplitScreenListener",
- (controller) -> {
- if (mListener != null) {
- mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- }
- mListener = null;
- controller.unregisterSplitScreenListener(mSplitScreenListener);
- });
+ public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
+ int sideStagePosition) {
+ return mMainExecutor.executeBlockingForResult(() -> {
+ return SplitScreenController.this.moveToSideStage(task, sideStagePosition);
+ }, Boolean.class);
}
@Override
- public void exitSplitScreen() {
- executeRemoteCallWithTaskPermission(mController, "exitSplitScreen",
- (controller) -> {
- controller.exitSplitScreen();
- });
+ public boolean removeFromSideStage(int taskId) {
+ return mMainExecutor.executeBlockingForResult(() -> {
+ return SplitScreenController.this.removeFromSideStage(taskId);
+ }, Boolean.class);
}
@Override
- public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
- executeRemoteCallWithTaskPermission(mController, "exitSplitScreenOnHide",
- (controller) -> {
- controller.exitSplitScreenOnHide(exitSplitScreenOnHide);
- });
+ public void setSideStagePosition(int sideStagePosition) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.setSideStagePosition(sideStagePosition);
+ });
}
@Override
public void setSideStageVisibility(boolean visible) {
- executeRemoteCallWithTaskPermission(mController, "setSideStageVisibility",
- (controller) -> {
- controller.setSideStageVisibility(visible);
- });
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.setSideStageVisibility(visible);
+ });
}
@Override
- public void removeFromSideStage(int taskId) {
- executeRemoteCallWithTaskPermission(mController, "removeFromSideStage",
- (controller) -> {
- controller.removeFromSideStage(taskId);
- });
+ public void enterSplitScreen(int taskId, boolean leftOrTop) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.enterSplitScreen(taskId, leftOrTop);
+ });
+ }
+
+ @Override
+ public void exitSplitScreen() {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.exitSplitScreen();
+ });
+ }
+
+ @Override
+ public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.exitSplitScreenOnHide(exitSplitScreenOnHide);
+ });
+ }
+
+ @Override
+ public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
+ try {
+ mMainExecutor.executeBlocking(() -> {
+ SplitScreenController.this.getStageBounds(outTopOrLeftBounds,
+ outBottomOrRightBounds);
+ });
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Failed to get stage bounds in 2s");
+ }
+ }
+
+ @Override
+ public void registerSplitScreenListener(SplitScreenListener listener) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.registerSplitScreenListener(listener);
+ });
+ }
+
+ @Override
+ public void unregisterSplitScreenListener(SplitScreenListener listener) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.unregisterSplitScreenListener(listener);
+ });
}
@Override
public void startTask(int taskId, int stage, int position, @Nullable Bundle options) {
- executeRemoteCallWithTaskPermission(mController, "startTask",
- (controller) -> {
- controller.startTask(taskId, stage, position, options);
- });
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.startTask(taskId, stage, position, options);
+ });
}
@Override
public void startShortcut(String packageName, String shortcutId, int stage, int position,
@Nullable Bundle options, UserHandle user) {
- executeRemoteCallWithTaskPermission(mController, "startShortcut",
- (controller) -> {
- controller.startShortcut(packageName, shortcutId, stage, position,
- options, user);
- });
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.startShortcut(packageName, shortcutId, stage, position,
+ options, user);
+ });
}
@Override
- public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, int position,
- @Nullable Bundle options) {
- executeRemoteCallWithTaskPermission(mController, "startIntent",
- (controller) -> {
- controller.startIntent(intent, fillInIntent, stage, position, options);
- });
+ public void startIntent(PendingIntent intent, Context context, Intent fillInIntent,
+ int stage, int position, @Nullable Bundle options) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.startIntent(intent, context, fillInIntent, stage,
+ position, options);
+ });
}
}
+
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindow.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindow.aidl
deleted file mode 100644
index 546c406..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindow.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2021 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.wm.shell.startingsurface;
-
-import com.android.wm.shell.startingsurface.IStartingWindowListener;
-
-/**
- * Interface that is exposed to remote callers to manipulate starting windows.
- */
-interface IStartingWindow {
- /**
- * Sets listener to get task launching callbacks.
- */
- oneway void setStartingWindowListener(IStartingWindowListener listener) = 43;
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
index 079d689..f258286 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
@@ -16,15 +16,35 @@
package com.android.wm.shell.startingsurface;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.view.SurfaceControl;
+import android.window.StartingWindowInfo;
+
+import java.util.function.BiConsumer;
/**
* Interface to engage starting window feature.
*/
public interface StartingSurface {
+ /**
+ * Called when a task need a starting window.
+ */
+ void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken);
+ /**
+ * Called when the content of a task is ready to show, starting window can be removed.
+ */
+ void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation);
+ /**
+ * Called when the Task wants to copy the splash screen.
+ * @param taskId
+ */
+ void copySplashScreenView(int taskId);
/**
- * Returns a binder that can be passed to an external process to manipulate starting windows.
+ * Registers the starting window listener.
+ *
+ * @param listener The callback when need a starting window.
*/
- default IStartingWindow createExternalInterface() {
- return null;
- }
+ void setStartingWindowListener(BiConsumer<Integer, Integer> listener);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index b6ca869..a694e52 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -25,8 +25,6 @@
import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
-
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.Context;
@@ -39,9 +37,6 @@
import android.window.TaskOrganizer;
import android.window.TaskSnapshot;
-import androidx.annotation.BinderThread;
-
-import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
@@ -63,7 +58,7 @@
* constructor to keep everything synchronized.
* @hide
*/
-public class StartingWindowController implements RemoteCallable<StartingWindowController> {
+public class StartingWindowController {
private static final String TAG = StartingWindowController.class.getSimpleName();
static final boolean DEBUG_SPLASH_SCREEN = false;
static final boolean DEBUG_TASK_SNAPSHOT = false;
@@ -73,17 +68,17 @@
private BiConsumer<Integer, Integer> mTaskLaunchingCallback;
private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
- private final Context mContext;
private final ShellExecutor mSplashScreenExecutor;
// For Car Launcher
public StartingWindowController(Context context, ShellExecutor splashScreenExecutor) {
- this(context, splashScreenExecutor, new TransactionPool());
+ mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor,
+ new TransactionPool());
+ mSplashScreenExecutor = splashScreenExecutor;
}
public StartingWindowController(Context context, ShellExecutor splashScreenExecutor,
TransactionPool pool) {
- mContext = context;
mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, pool);
mSplashScreenExecutor = splashScreenExecutor;
}
@@ -95,16 +90,6 @@
return mImpl;
}
- @Override
- public Context getContext() {
- return mContext;
- }
-
- @Override
- public ShellExecutor getRemoteCallExecutor() {
- return mSplashScreenExecutor;
- }
-
private static class StartingTypeChecker {
TaskSnapshot mSnapshot;
@@ -203,121 +188,59 @@
/**
* Called when a task need a starting window.
*/
- public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
- mSplashScreenExecutor.execute(() -> {
- final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
- final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
- if (mTaskLaunchingCallback != null) {
- mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType);
- }
- if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
- mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken);
- } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
- final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot;
- mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
- }
- // If prefer don't show, then don't show!
- });
+ void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+ final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
+ final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
+ if (mTaskLaunchingCallback != null) {
+ mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType);
+ }
+ if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
+ mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken);
+ } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
+ final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot;
+ mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
+ }
+ // If prefer don't show, then don't show!
}
- public void copySplashScreenView(int taskId) {
- mSplashScreenExecutor.execute(() -> {
- mStartingSurfaceDrawer.copySplashScreenView(taskId);
- });
+ void copySplashScreenView(int taskId) {
+ mStartingSurfaceDrawer.copySplashScreenView(taskId);
}
/**
* Called when the content of a task is ready to show, starting window can be removed.
*/
- public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
boolean playRevealAnimation) {
- mSplashScreenExecutor.execute(() -> {
- mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
- });
+ mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
}
- /**
- * The interface for calls from outside the Shell, within the host process.
- */
private class StartingSurfaceImpl implements StartingSurface {
- private IStartingWindowImpl mIStartingWindow;
@Override
- public IStartingWindowImpl createExternalInterface() {
- if (mIStartingWindow != null) {
- mIStartingWindow.invalidate();
- }
- mIStartingWindow = new IStartingWindowImpl(StartingWindowController.this);
- return mIStartingWindow;
- }
- }
-
- /**
- * The interface for calls from outside the host process.
- */
- @BinderThread
- private static class IStartingWindowImpl extends IStartingWindow.Stub {
- private StartingWindowController mController;
- private IStartingWindowListener mListener;
- private final BiConsumer<Integer, Integer> mStartingWindowListener =
- this::notifyIStartingWindowListener;
- private final IBinder.DeathRecipient mListenerDeathRecipient =
- new IBinder.DeathRecipient() {
- @Override
- @BinderThread
- public void binderDied() {
- final StartingWindowController controller = mController;
- controller.getRemoteCallExecutor().execute(() -> {
- mListener = null;
- controller.setStartingWindowListener(null);
- });
- }
- };
-
- public IStartingWindowImpl(StartingWindowController controller) {
- mController = controller;
- }
-
- /**
- * Invalidates this instance, preventing future calls from updating the controller.
- */
- void invalidate() {
- mController = null;
+ public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+ mSplashScreenExecutor.execute(() ->
+ StartingWindowController.this.addStartingWindow(windowInfo, appToken));
}
@Override
- public void setStartingWindowListener(IStartingWindowListener listener) {
- executeRemoteCallWithTaskPermission(mController, "setStartingWindowListener",
- (controller) -> {
- if (mListener != null) {
- // Reset the old death recipient
- mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- }
- if (listener != null) {
- try {
- listener.asBinder().linkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to link to death");
- return;
- }
- }
- mListener = listener;
- controller.setStartingWindowListener(mStartingWindowListener);
- });
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
+ mSplashScreenExecutor.execute(() ->
+ StartingWindowController.this.removeStartingWindow(taskId, leash, frame,
+ playRevealAnimation));
}
- private void notifyIStartingWindowListener(int taskId, int supportedType) {
- if (mListener == null) {
- return;
- }
+ @Override
+ public void copySplashScreenView(int taskId) {
+ mSplashScreenExecutor.execute(() ->
+ StartingWindowController.this.copySplashScreenView(taskId));
+ }
- try {
- mListener.onTaskLaunching(taskId, supportedType);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to notify task launching", e);
- }
+ @Override
+ public void setStartingWindowListener(BiConsumer<Integer, Integer> listener) {
+ mSplashScreenExecutor.execute(() ->
+ StartingWindowController.this.setStartingWindowListener(listener));
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
deleted file mode 100644
index dffc700..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2021 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.wm.shell.transition;
-
-import android.window.IRemoteTransition;
-import android.window.TransitionFilter;
-
-/**
- * Interface that is exposed to remote callers to manipulate the transitions feature.
- */
-interface IShellTransitions {
-
- /**
- * Registers a remote transition handler.
- */
- oneway void registerRemote(in TransitionFilter filter,
- in IRemoteTransition remoteTransition) = 1;
-
- /**
- * Unregisters a remote transition handler.
- */
- oneway void unregisterRemote(in IRemoteTransition remoteTransition) = 2;
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index 9667f4b..ac93a17 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -16,8 +16,6 @@
package com.android.wm.shell.transition;
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IBinder;
@@ -25,7 +23,6 @@
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
-import android.util.Slog;
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
@@ -34,8 +31,6 @@
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
-import androidx.annotation.BinderThread;
-
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -47,8 +42,6 @@
* if the request includes a specific remote.
*/
public class RemoteTransitionHandler implements Transitions.TransitionHandler {
- private static final String TAG = "RemoteTransitionHandler";
-
private final ShellExecutor mMainExecutor;
/** Includes remotes explicitly requested by, eg, ActivityOptions */
@@ -58,33 +51,15 @@
private final ArrayList<Pair<TransitionFilter, IRemoteTransition>> mFilters =
new ArrayList<>();
- private final IBinder.DeathRecipient mTransitionDeathRecipient =
- new IBinder.DeathRecipient() {
- @Override
- @BinderThread
- public void binderDied() {
- mMainExecutor.execute(() -> {
- mFilters.clear();
- });
- }
- };
-
RemoteTransitionHandler(@NonNull ShellExecutor mainExecutor) {
mMainExecutor = mainExecutor;
}
void addFiltered(TransitionFilter filter, IRemoteTransition remote) {
- try {
- remote.asBinder().linkToDeath(mTransitionDeathRecipient, 0 /* flags */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to link to death");
- return;
- }
mFilters.add(new Pair<>(filter, remote));
}
void removeFiltered(IRemoteTransition remote) {
- remote.asBinder().unlinkToDeath(mTransitionDeathRecipient, 0 /* flags */);
for (int i = mFilters.size() - 1; i >= 0; --i) {
if (mFilters.get(i).second == remote) {
mFilters.remove(i);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
similarity index 83%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
index bc42c6e..85bbf74 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
@@ -26,15 +26,7 @@
* Interface to manage remote transitions.
*/
@ExternalThread
-public interface ShellTransitions {
-
- /**
- * Returns a binder that can be passed to an external process to manipulate remote transitions.
- */
- default IShellTransitions createExternalInterface() {
- return null;
- }
-
+public interface RemoteTransitions {
/**
* Registers a remote transition.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index ca1b53d..677db10 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -23,8 +23,6 @@
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
@@ -53,7 +51,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ExternalThread;
@@ -63,7 +60,7 @@
import java.util.Arrays;
/** Plays transition animations */
-public class Transitions implements RemoteCallable<Transitions> {
+public class Transitions {
static final String TAG = "ShellTransitions";
/** Set to {@code true} to enable shell transitions. */
@@ -76,7 +73,7 @@
private final ShellExecutor mAnimExecutor;
private final TransitionPlayerImpl mPlayerImpl;
private final RemoteTransitionHandler mRemoteTransitionHandler;
- private final ShellTransitionImpl mImpl = new ShellTransitionImpl();
+ private final RemoteTransitionImpl mImpl = new RemoteTransitionImpl();
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
@@ -90,6 +87,10 @@
/** Keeps track of currently tracked transitions and all the animations associated with each */
private final ArrayMap<IBinder, ActiveTransition> mActiveTransitions = new ArrayMap<>();
+ public static RemoteTransitions asRemoteTransitions(Transitions transitions) {
+ return transitions.mImpl;
+ }
+
public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
@NonNull Context context, @NonNull ShellExecutor mainExecutor,
@NonNull ShellExecutor animExecutor) {
@@ -125,20 +126,6 @@
mRemoteTransitionHandler = null;
}
- public ShellTransitions asRemoteTransitions() {
- return mImpl;
- }
-
- @Override
- public Context getContext() {
- return mContext;
- }
-
- @Override
- public ShellExecutor getRemoteCallExecutor() {
- return mMainExecutor;
- }
-
private void dispatchAnimScaleSetting(float scale) {
for (int i = mHandlers.size() - 1; i >= 0; --i) {
mHandlers.get(i).setAnimScaleSetting(scale);
@@ -147,8 +134,8 @@
/** Create an empty/non-registering transitions object for system-ui tests. */
@VisibleForTesting
- public static ShellTransitions createEmptyForTesting() {
- return new ShellTransitions() {
+ public static RemoteTransitions createEmptyForTesting() {
+ return new RemoteTransitions() {
@Override
public void registerRemote(@androidx.annotation.NonNull TransitionFilter filter,
@androidx.annotation.NonNull IRemoteTransition remoteTransition) {
@@ -439,74 +426,24 @@
}
}
- /**
- * The interface for calls from outside the Shell, within the host process.
- */
@ExternalThread
- private class ShellTransitionImpl implements ShellTransitions {
- private IShellTransitionsImpl mIShellTransitions;
-
- @Override
- public IShellTransitions createExternalInterface() {
- if (mIShellTransitions != null) {
- mIShellTransitions.invalidate();
- }
- mIShellTransitions = new IShellTransitionsImpl(Transitions.this);
- return mIShellTransitions;
- }
-
+ private class RemoteTransitionImpl implements RemoteTransitions {
@Override
public void registerRemote(@NonNull TransitionFilter filter,
@NonNull IRemoteTransition remoteTransition) {
mMainExecutor.execute(() -> {
- mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
+ Transitions.this.registerRemote(filter, remoteTransition);
});
}
@Override
public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
mMainExecutor.execute(() -> {
- mRemoteTransitionHandler.removeFiltered(remoteTransition);
+ Transitions.this.unregisterRemote(remoteTransition);
});
}
}
- /**
- * The interface for calls from outside the host process.
- */
- @BinderThread
- private static class IShellTransitionsImpl extends IShellTransitions.Stub {
- private Transitions mTransitions;
-
- IShellTransitionsImpl(Transitions transitions) {
- mTransitions = transitions;
- }
-
- /**
- * Invalidates this instance, preventing future calls from updating the controller.
- */
- void invalidate() {
- mTransitions = null;
- }
-
- @Override
- public void registerRemote(@NonNull TransitionFilter filter,
- @NonNull IRemoteTransition remoteTransition) {
- executeRemoteCallWithTaskPermission(mTransitions, "registerRemote",
- (transitions) -> {
- transitions.mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
- });
- }
-
- @Override
- public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
- executeRemoteCallWithTaskPermission(mTransitions, "unregisterRemote",
- (transitions) -> {
- transitions.mRemoteTransitionHandler.removeFiltered(remoteTransition);
- });
- }
- }
-
private class SettingsObserver extends ContentObserver {
SettingsObserver() {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 2f2bbba..c1c4c6d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -205,7 +205,7 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
}
@@ -217,12 +217,12 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@@ -234,12 +234,12 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@@ -251,7 +251,7 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
}
@@ -263,7 +263,7 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
}
@@ -276,13 +276,13 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
// TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@@ -295,13 +295,13 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
// TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(), any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index b4db305..5f44b62 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -21,6 +21,7 @@
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -89,6 +90,7 @@
private final CopyOnWriteArrayList<ControllerCreationRequest> mControllerCreationRequests =
new CopyOnWriteArrayList<>();
+ // TODO: Specify the fields that are only used (or not used) by system media router.
private final String mClientPackageName;
private final ManagerCallback mManagerCallback;
@@ -132,18 +134,34 @@
}
/**
- * Gets an instance of the media router which controls the app's media routing.
+ * Gets an instance of the system media router which controls the app's media routing.
* Returns {@code null} if the given package name is invalid.
+ * There are several things to note when using the media routers created with this method.
* <p>
- * Note: For media routers created with this method, the discovery preference passed to
- * {@link #registerRouteCallback} will have no effect. The callback will be called accordingly
- * with the client app's discovery preference. Therefore, it is recommended to pass
+ * First of all, the discovery preference passed to {@link #registerRouteCallback}
+ * will have no effect. The callback will be called accordingly with the client app's
+ * discovery preference. Therefore, it is recommended to pass
* {@link RouteDiscoveryPreference#EMPTY} there.
+ * <p>
+ * Also, do not keep/compare the instances of the {@link RoutingController}, since they are
+ * always newly created with the latest session information whenever below methods are called:
+ * <ul>
+ * <li> {@link #getControllers()} </li>
+ * <li> {@link #getController(String)}} </li>
+ * <li> {@link TransferCallback#onTransfer(RoutingController, RoutingController)} </li>
+ * <li> {@link TransferCallback#onStop(RoutingController)} </li>
+ * <li> {@link ControllerCallback#onControllerUpdated(RoutingController)} </li>
+ * </ul>
+ * Therefore, in order to track the current routing status, keep the controller's ID instead,
+ * and use {@link #getController(String)} and {@link #getSystemController()} for
+ * getting controllers.
+ * <p>
+ * Finally, it will have no effect to call {@link #setOnGetControllerHintsListener}.
*
* @param clientPackageName the package name of the app to control
* @hide
*/
- //@SystemApi
+ @SystemApi
@Nullable
public static MediaRouter2 getInstance(@NonNull Context context,
@NonNull String clientPackageName) {
@@ -168,12 +186,40 @@
instance = new MediaRouter2(context, clientPackageName);
sSystemMediaRouter2Map.put(clientPackageName, instance);
// TODO: Remove router instance once it is not needed.
- instance.registerManagerCallback();
+ instance.registerManagerCallbackForSystemRouter();
}
return instance;
}
}
+ /**
+ * Starts scanning remote routes.
+ * Note that calling start/stopScan is applied to all system routers in the same process.
+ *
+ * @see #stopScan()
+ * @hide
+ */
+ @SystemApi
+ public void startScan() {
+ if (isSystemRouter()) {
+ sManager.startScan();
+ }
+ }
+
+ /**
+ * Stops scanning remote routes to reduce resource consumption.
+ * Note that calling start/stopScan is applied to all system routers in the same process.
+ *
+ * @see #startScan()
+ * @hide
+ */
+ @SystemApi
+ public void stopScan() {
+ if (isSystemRouter()) {
+ sManager.stopScan();
+ }
+ }
+
private MediaRouter2(Context appContext) {
mContext = appContext;
mMediaRouterService = IMediaRouterService.Stub.asInterface(
@@ -209,13 +255,15 @@
}
private MediaRouter2(Context context, String clientPackageName) {
+ mContext = context;
mClientPackageName = clientPackageName;
mManagerCallback = new ManagerCallback();
- mContext = context;
- mMediaRouterService = null;
- mPackageName = null;
mHandler = new Handler(Looper.getMainLooper());
- mSystemController = null;
+ mSystemController = new SystemRoutingController(sManager.getSystemRoutingSession());
+ mMediaRouterService = null; // TODO: Make this non-null and check permission.
+
+ // Only used by non-system MediaRouter2.
+ mPackageName = null;
}
/**
@@ -240,7 +288,7 @@
* @see #getInstance(Context, String)
* @hide
*/
- //@SystemApi
+ @SystemApi
@Nullable
public String getClientPackageName() {
return mClientPackageName;
@@ -358,7 +406,8 @@
*
* @hide
*/
- //@SystemApi
+ @SystemApi
+ @NonNull
public List<MediaRoute2Info> getAllRoutes() {
if (isSystemRouter()) {
return sManager.getAllRoutes();
@@ -377,10 +426,6 @@
*/
@NonNull
public List<MediaRoute2Info> getRoutes() {
- if (isSystemRouter()) {
- return sManager.getAvailableRoutes(mClientPackageName);
- }
-
synchronized (mLock) {
if (mShouldUpdateRoutes) {
mShouldUpdateRoutes = false;
@@ -474,6 +519,9 @@
* {@code null} for unset.
*/
public void setOnGetControllerHintsListener(@Nullable OnGetControllerHintsListener listener) {
+ if (isSystemRouter()) {
+ return;
+ }
mOnGetControllerHintsListener = listener;
}
@@ -519,7 +567,7 @@
* @param route the route you want to transfer the media to.
* @hide
*/
- //@SystemApi
+ @SystemApi
public void transfer(@NonNull RoutingController controller, @NonNull MediaRoute2Info route) {
if (isSystemRouter()) {
sManager.transfer(controller.getRoutingSessionInfo(), route);
@@ -606,6 +654,23 @@
}
/**
+ * Gets a {@link RoutingController} whose ID is equal to the given ID.
+ * Returns {@code null} if there is no matching controller.
+ * @hide
+ */
+ @SystemApi
+ @Nullable
+ public RoutingController getController(@NonNull String id) {
+ Objects.requireNonNull(id, "id must not be null");
+ for (RoutingController controller : getControllers()) {
+ if (TextUtils.equals(id, controller.getId())) {
+ return controller;
+ }
+ }
+ return null;
+ }
+
+ /**
* Gets the list of currently active {@link RoutingController routing controllers} on which
* media can be played.
* <p>
@@ -614,15 +679,25 @@
*/
@NonNull
public List<RoutingController> getControllers() {
- // TODO: Do not create the controller instances every time,
- // Instead, update the list using the sessions' ID and session related callbacks.
+ List<RoutingController> result = new ArrayList<>();
+
if (isSystemRouter()) {
- return sManager.getRoutingSessions(mClientPackageName).stream()
- .map(info -> new RoutingController(info))
- .collect(Collectors.toList());
+ // Unlike non-system MediaRouter2, controller instances cannot be kept,
+ // since the transfer events initiated from other apps will not come through manager.
+ List<RoutingSessionInfo> sessions = sManager.getRoutingSessions(mClientPackageName);
+ for (RoutingSessionInfo session : sessions) {
+ RoutingController controller;
+ if (session.isSystemSession()) {
+ mSystemController.setRoutingSessionInfo(session);
+ controller = mSystemController;
+ } else {
+ controller = new RoutingController(session);
+ }
+ result.add(controller);
+ }
+ return result;
}
- List<RoutingController> result = new ArrayList<>();
result.add(0, mSystemController);
synchronized (mLock) {
result.addAll(mNonSystemRoutingControllers.values());
@@ -639,9 +714,15 @@
* @param volume The new volume value between 0 and {@link MediaRoute2Info#getVolumeMax}.
* @hide
*/
+ @SystemApi
public void setRouteVolume(@NonNull MediaRoute2Info route, int volume) {
Objects.requireNonNull(route, "route must not be null");
+ if (isSystemRouter()) {
+ sManager.setRouteVolume(route, volume);
+ return;
+ }
+
MediaRouter2Stub stub;
synchronized (mLock) {
stub = mStub;
@@ -928,8 +1009,9 @@
/**
* Registers {@link MediaRouter2Manager.Callback} for getting events.
+ * Should only used for system media routers.
*/
- private void registerManagerCallback() {
+ private void registerManagerCallbackForSystemRouter() {
// Using direct executor here, since MediaRouter2Manager also posts to the main handler.
sManager.registerCallback(Runnable::run, mManagerCallback);
}
@@ -941,6 +1023,16 @@
.collect(Collectors.toList());
}
+ private void updateAllRoutesFromManager() {
+ synchronized (mLock) {
+ mRoutes.clear();
+ for (MediaRoute2Info route : sManager.getAllRoutes()) {
+ mRoutes.put(route.getId(), route);
+ }
+ mShouldUpdateRoutes = true;
+ }
+ }
+
private void notifyRoutesAdded(List<MediaRoute2Info> routes) {
for (RouteCallbackRecord record: mRouteCallbackRecords) {
List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mPreference);
@@ -971,6 +1063,13 @@
}
}
+ private void notifyPreferredFeaturesChanged(List<String> features) {
+ for (RouteCallbackRecord record: mRouteCallbackRecords) {
+ record.mExecutor.execute(
+ () -> record.mRouteCallback.onPreferredFeaturesChanged(features));
+ }
+ }
+
private void notifyTransfer(RoutingController oldController, RoutingController newController) {
for (TransferCallbackRecord record: mTransferCallbackRecords) {
record.mExecutor.execute(
@@ -1024,6 +1123,17 @@
* @param routes the list of routes that have been changed. It's never empty.
*/
public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
+
+ /**
+ * Called when the client app's preferred features are changed.
+ * When this is called, it is recommended to {@link #getRoutes()} to get the routes
+ * that are currently available to the app.
+ *
+ * @param preferredFeatures the new preferred features set by the application
+ * @hide
+ */
+ @SystemApi
+ public void onPreferredFeaturesChanged(@NonNull List<String> preferredFeatures) {}
}
/**
@@ -1131,6 +1241,11 @@
mState = CONTROLLER_STATE_ACTIVE;
}
+ RoutingController(@NonNull RoutingSessionInfo sessionInfo, int state) {
+ mSessionInfo = sessionInfo;
+ mState = state;
+ }
+
/**
* @return the ID of the controller. It is globally unique.
*/
@@ -1291,6 +1406,11 @@
return;
}
+ if (isSystemRouter()) {
+ sManager.selectRoute(getRoutingSessionInfo(), route);
+ return;
+ }
+
MediaRouter2Stub stub;
synchronized (mLock) {
stub = mStub;
@@ -1338,6 +1458,11 @@
return;
}
+ if (isSystemRouter()) {
+ sManager.deselectRoute(getRoutingSessionInfo(), route);
+ return;
+ }
+
MediaRouter2Stub stub;
synchronized (mLock) {
stub = mStub;
@@ -1407,6 +1532,12 @@
Log.w(TAG, "setVolume: Called on released controller. Ignoring.");
return;
}
+
+ if (isSystemRouter()) {
+ sManager.setSessionVolume(getRoutingSessionInfo(), volume);
+ return;
+ }
+
MediaRouter2Stub stub;
synchronized (mLock) {
stub = mStub;
@@ -1471,6 +1602,11 @@
mState = CONTROLLER_STATE_RELEASED;
}
+ if (isSystemRouter()) {
+ sManager.releaseSession(getRoutingSessionInfo());
+ return;
+ }
+
synchronized (mLock) {
mNonSystemRoutingControllers.remove(getId(), this);
@@ -1539,6 +1675,12 @@
}
private List<MediaRoute2Info> getRoutesWithIds(List<String> routeIds) {
+ if (isSystemRouter()) {
+ return getRoutes().stream()
+ .filter(r -> routeIds.contains(r.getId()))
+ .collect(Collectors.toList());
+ }
+
synchronized (mLock) {
return routeIds.stream().map(mRoutes::get)
.filter(Objects::nonNull)
@@ -1722,12 +1864,17 @@
}
}
+ // Note: All methods are run on main thread.
class ManagerCallback implements MediaRouter2Manager.Callback {
@Override
public void onRoutesAdded(@NonNull List<MediaRoute2Info> routes) {
- List<MediaRoute2Info> filteredRoutes =
- sManager.filterRoutesForPackage(routes, mClientPackageName);
+ updateAllRoutesFromManager();
+
+ List<MediaRoute2Info> filteredRoutes;
+ synchronized (mLock) {
+ filteredRoutes = filterRoutes(routes, mDiscoveryPreference);
+ }
if (filteredRoutes.isEmpty()) {
return;
}
@@ -1739,8 +1886,12 @@
@Override
public void onRoutesRemoved(@NonNull List<MediaRoute2Info> routes) {
- List<MediaRoute2Info> filteredRoutes =
- sManager.filterRoutesForPackage(routes, mClientPackageName);
+ updateAllRoutesFromManager();
+
+ List<MediaRoute2Info> filteredRoutes;
+ synchronized (mLock) {
+ filteredRoutes = filterRoutes(routes, mDiscoveryPreference);
+ }
if (filteredRoutes.isEmpty()) {
return;
}
@@ -1752,8 +1903,12 @@
@Override
public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {
- List<MediaRoute2Info> filteredRoutes =
- sManager.filterRoutesForPackage(routes, mClientPackageName);
+ updateAllRoutesFromManager();
+
+ List<MediaRoute2Info> filteredRoutes;
+ synchronized (mLock) {
+ filteredRoutes = filterRoutes(routes, mDiscoveryPreference);
+ }
if (filteredRoutes.isEmpty()) {
return;
}
@@ -1764,31 +1919,98 @@
}
@Override
- public void onSessionUpdated(@NonNull RoutingSessionInfo session) {
- // TODO: Call ControllerCallback.onControllerUpdated
- }
-
- @Override
public void onTransferred(@NonNull RoutingSessionInfo oldSession,
- @Nullable RoutingSessionInfo newSession) {
- // TODO: Call TransferCallback.onTransfer
+ @NonNull RoutingSessionInfo newSession) {
+ if (!oldSession.isSystemSession()
+ && !TextUtils.equals(mClientPackageName, oldSession.getClientPackageName())) {
+ return;
+ }
+
+ if (!newSession.isSystemSession()
+ && !TextUtils.equals(mClientPackageName, newSession.getClientPackageName())) {
+ return;
+ }
+
+ // For successful in-session transfer, onControllerUpdated() handles it.
+ if (TextUtils.equals(oldSession.getId(), newSession.getId())) {
+ return;
+ }
+
+
+ RoutingController oldController;
+ if (oldSession.isSystemSession()) {
+ mSystemController.setRoutingSessionInfo(oldSession);
+ oldController = mSystemController;
+ } else {
+ oldController = new RoutingController(oldSession);
+ }
+
+ RoutingController newController;
+ if (oldSession.isSystemSession()) {
+ mSystemController.setRoutingSessionInfo(newSession);
+ newController = mSystemController;
+ } else {
+ newController = new RoutingController(newSession);
+ }
+
+ notifyTransfer(oldController, newController);
}
@Override
public void onTransferFailed(@NonNull RoutingSessionInfo session,
@NonNull MediaRoute2Info route) {
- // TODO: Call TransferCallback.onTransferFailure
+ if (!session.isSystemSession()
+ && !TextUtils.equals(mClientPackageName, session.getClientPackageName())) {
+ return;
+ }
+ notifyTransferFailure(route);
+ }
+
+ @Override
+ public void onSessionUpdated(@NonNull RoutingSessionInfo session) {
+ if (!session.isSystemSession()
+ && !TextUtils.equals(mClientPackageName, session.getClientPackageName())) {
+ return;
+ }
+
+ RoutingController controller;
+ if (session.isSystemSession()) {
+ mSystemController.setRoutingSessionInfo(session);
+ controller = mSystemController;
+ } else {
+ controller = new RoutingController(session);
+ }
+ notifyControllerUpdated(controller);
}
@Override
public void onSessionReleased(@NonNull RoutingSessionInfo session) {
- // TODO: Call TransferCallback.onStop()
+ if (session.isSystemSession()) {
+ Log.e(TAG, "onSessionReleased: Called on system session. Ignoring.");
+ return;
+ }
+
+ if (!TextUtils.equals(mClientPackageName, session.getClientPackageName())) {
+ return;
+ }
+
+ notifyStop(new RoutingController(session, RoutingController.CONTROLLER_STATE_RELEASED));
}
@Override
public void onPreferredFeaturesChanged(@NonNull String packageName,
@NonNull List<String> preferredFeatures) {
- // Does nothing.
+ if (!TextUtils.equals(mClientPackageName, packageName)) {
+ return;
+ }
+
+ synchronized (mLock) {
+ mDiscoveryPreference = new RouteDiscoveryPreference.Builder(
+ preferredFeatures, true).build();
+ }
+
+ updateAllRoutesFromManager();
+ notifyPreferredFeaturesChanged(preferredFeatures);
}
@Override
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index ca619d4..20e3573 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -148,7 +148,7 @@
/**
* Starts scanning remote routes.
- * @see #stopScan(String)
+ * @see #stopScan()
*/
public void startScan() {
Client client = getOrCreateClient();
@@ -163,7 +163,7 @@
/**
* Stops scanning remote routes to reduce resource consumption.
- * @see #startScan(String)
+ * @see #startScan()
*/
public void stopScan() {
Client client = getOrCreateClient();
@@ -788,8 +788,8 @@
* Requests releasing a session.
* <p>
* If a session is released, any operation on the session will be ignored.
- * {@link Callback#onTransferred(RoutingSessionInfo, RoutingSessionInfo)} with {@code null}
- * session will be called when the session is released.
+ * {@link Callback#onSessionReleased(RoutingSessionInfo)} will be called
+ * when the session is released.
* </p>
*
* @see Callback#onTransferred(RoutingSessionInfo, RoutingSessionInfo)
@@ -945,10 +945,10 @@
* Called when media is transferred.
*
* @param oldSession the previous session
- * @param newSession the new session or {@code null} if the session is released.
+ * @param newSession the new session
*/
default void onTransferred(@NonNull RoutingSessionInfo oldSession,
- @Nullable RoutingSessionInfo newSession) { }
+ @NonNull RoutingSessionInfo newSession) { }
/**
* Called when {@link #transfer(RoutingSessionInfo, MediaRoute2Info)} fails.
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index b6fd286..6574353 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -54,7 +54,7 @@
name: "SystemUI-sensors",
srcs: [
"src/com/android/systemui/util/sensors/ThresholdSensor.java",
- ]
+ ],
}
android_library {
@@ -99,7 +99,7 @@
"SystemUI-tags",
"SystemUI-proto",
"dagger2",
- "jsr330"
+ "jsr330",
],
manifest: "AndroidManifest.xml",
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp
index 9e67e4b..d6204db 100644
--- a/packages/SystemUI/plugin/Android.bp
+++ b/packages/SystemUI/plugin/Android.bp
@@ -25,7 +25,10 @@
name: "SystemUIPluginLib",
- srcs: ["src/**/*.java"],
+ srcs: [
+ "src/**/*.java",
+ "bcsmartspace/src/**/*.java",
+ ],
static_libs: [
"PluginCoreLib",
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
new file mode 100644
index 0000000..f8a9a045
--- /dev/null
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 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.os.Parcelable;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+import java.util.List;
+
+/**
+ * Interface to provide SmartspaceTargets to BcSmartspace.
+ */
+@ProvidesInterface(action = BcSmartspaceDataPlugin.ACTION, version = BcSmartspaceDataPlugin.VERSION)
+public interface BcSmartspaceDataPlugin extends Plugin {
+ String ACTION = "com.android.systemui.action.PLUGIN_BC_SMARTSPACE_DATA";
+ int VERSION = 1;
+
+ /** Register a listener to get Smartspace data. */
+ void registerListener(SmartspaceTargetListener listener);
+
+ /** Unregister a listener. */
+ void unregisterListener(SmartspaceTargetListener listener);
+
+ /** Provides Smartspace data to registered listeners. */
+ interface SmartspaceTargetListener {
+ /** Each Parcelable is a SmartspaceTarget that represents a card. */
+ void onSmartspaceTargetsUpdated(List<? extends Parcelable> targets);
+ }
+}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 70be7c6..a8083f1 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -851,8 +851,6 @@
<string name="quick_settings_wifi_label">Wi-Fi</string>
<!-- QuickSettings: Internet [CHAR LIMIT=NONE] -->
<string name="quick_settings_internet_label">Internet</string>
- <!-- QuickSettings: Airplane-safe [CHAR LIMIT=NONE] -->
- <string name="quick_settings_airplane_safe_label">Airplane-safe</string>
<!-- QuickSettings: networks available [CHAR LIMIT=NONE] -->
<string name="quick_settings_networks_available">Networks available</string>
<!-- QuickSettings: networks unavailable [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index f98a959..09e9675a 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -41,7 +41,6 @@
srcs: [
"src/**/*.java",
"src/**/I*.aidl",
- ":wm_shell-aidls",
],
static_libs: [
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl
similarity index 68%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
rename to packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl
index 2569b78..97aa512 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl
@@ -14,14 +14,15 @@
* limitations under the License.
*/
-package com.android.wm.shell.pip;
+package com.android.systemui.shared.recents;
/**
- * Listener interface that Launcher attaches to SystemUI to get Pip animation callbacks.
+ * Listener interface that Launcher attaches to SystemUI to get
+ * pinned stack animation callbacks.
*/
-oneway interface IPipAnimationListener {
+oneway interface IPinnedStackAnimationListener {
/**
- * Notifies the listener that the Pip animation is started.
+ * Notifies the pinned stack animation is started.
*/
- void onPipAnimationStarted();
+ void onPinnedStackAnimationStarted();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreenListener.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
similarity index 83%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreenListener.aidl
rename to packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
index faab4c2..54242be 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreenListener.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
@@ -14,20 +14,12 @@
* limitations under the License.
*/
-package com.android.wm.shell.splitscreen;
+package com.android.systemui.shared.recents;
/**
* Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
*/
oneway interface ISplitScreenListener {
-
- /**
- * Called when the stage position changes.
- */
void onStagePositionChanged(int stage, int position);
-
- /**
- * Called when a task changes stages.
- */
void onTaskStageChanged(int taskId, int stage, boolean visible);
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindowListener.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl
similarity index 90%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindowListener.aidl
rename to packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl
index f562c8f..eb3e60c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindowListener.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.startingsurface;
+package com.android.systemui.shared.recents;
/**
* Listener interface that Launcher attaches to SystemUI to get
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 3da3085..5126284 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -16,6 +16,11 @@
package com.android.systemui.shared.recents;
+import android.app.PendingIntent;
+import android.app.PictureInPictureParams;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -23,15 +28,26 @@
import android.os.UserHandle;
import android.view.MotionEvent;
+import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
+import com.android.systemui.shared.recents.ISplitScreenListener;
+import com.android.systemui.shared.recents.IStartingWindowListener;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteTransitionCompat;
/**
* Temporary callbacks into SystemUI.
+ * Next id = 44
*/
interface ISystemUiProxy {
/**
+ * Proxies SurfaceControl.screenshotToBuffer().
+ * @Removed
+ * GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer,
+ * int maxLayer, boolean useIdentityTransform, int rotation) = 0;
+ */
+
+ /**
* Begins screen pinning on the provided {@param taskId}.
*/
void startScreenPinning(int taskId) = 1;
@@ -99,6 +115,11 @@
void stopScreenPinning() = 17;
/**
+ * Sets the shelf height and visibility.
+ */
+ void setShelfHeight(boolean visible, int shelfHeight) = 20;
+
+ /**
* Handle the provided image as if it was a screenshot.
*
* Deprecated, use handleImageBundleAsScreenshot with image bundle and UserTask
@@ -118,12 +139,27 @@
void notifySwipeToHomeFinished() = 23;
/**
+ * Sets listener to get pinned stack animation callbacks.
+ */
+ void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) = 24;
+
+ /**
* Notifies that quickstep will switch to a new task
* @param rotation indicates which Surface.Rotation the gesture was started in
*/
void onQuickSwitchToNewTask(int rotation) = 25;
/**
+ * Start the one-handed mode.
+ */
+ void startOneHandedMode() = 26;
+
+ /**
+ * Stop the one-handed mode.
+ */
+ void stopOneHandedMode() = 27;
+
+ /**
* Handle the provided image as if it was a screenshot.
*/
void handleImageBundleAsScreenshot(in Bundle screenImageBundle, in Rect locationInScreen,
@@ -134,5 +170,88 @@
*/
void expandNotificationPanel() = 29;
- // Next id = 44
+ /**
+ * Notifies that Activity is about to be swiped to home with entering PiP transition and
+ * queries the destination bounds for PiP depends on Launcher's rotation and shelf height.
+ *
+ * @param componentName ComponentName represents the Activity
+ * @param activityInfo ActivityInfo tied to the Activity
+ * @param pictureInPictureParams PictureInPictureParams tied to the Activity
+ * @param launcherRotation Launcher rotation to calculate the PiP destination bounds
+ * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds
+ * @return destination bounds the PiP window should land into
+ */
+ Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo,
+ in PictureInPictureParams pictureInPictureParams,
+ int launcherRotation, int shelfHeight) = 30;
+
+ /**
+ * Notifies the swiping Activity to PiP onto home transition is finished
+ *
+ * @param componentName ComponentName represents the Activity
+ * @param destinationBounds the destination bounds the PiP window lands into
+ */
+ void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 31;
+
+ /**
+ * Registers a RemoteTransitionCompat that will handle transitions. This parameter bundles an
+ * IRemoteTransition and a filter that must pass for it.
+ */
+ void registerRemoteTransition(in RemoteTransitionCompat remoteTransition) = 32;
+
+ /** Unegisters a RemoteTransitionCompat that will handle transitions. */
+ void unregisterRemoteTransition(in RemoteTransitionCompat remoteTransition) = 33;
+
+// SplitScreen APIs...copied from SplitScreen.java
+ /**
+ * Stage position isn't specified normally meaning to use what ever it is currently set to.
+ */
+ //int STAGE_POSITION_UNDEFINED = -1;
+ /**
+ * Specifies that a stage is positioned at the top half of the screen if
+ * in portrait mode or at the left half of the screen if in landscape mode.
+ */
+ //int STAGE_POSITION_TOP_OR_LEFT = 0;
+ /**
+ * Specifies that a stage is positioned at the bottom half of the screen if
+ * in portrait mode or at the right half of the screen if in landscape mode.
+ */
+ //int STAGE_POSITION_BOTTOM_OR_RIGHT = 1;
+
+ /**
+ * Stage type isn't specified normally meaning to use what ever the default is.
+ * E.g. exit split-screen and launch the app in fullscreen.
+ */
+ //int STAGE_TYPE_UNDEFINED = -1;
+ /**
+ * The main stage type.
+ * @see MainStage
+ */
+ //int STAGE_TYPE_MAIN = 0;
+ /**
+ * The side stage type.
+ * @see SideStage
+ */
+ //int STAGE_TYPE_SIDE = 1;
+
+ void registerSplitScreenListener(in ISplitScreenListener listener) = 34;
+ void unregisterSplitScreenListener(in ISplitScreenListener listener) = 35;
+
+ /** Hides the side-stage if it is currently visible. */
+ void setSideStageVisibility(in boolean visible) = 36;
+ /** Removes the split-screen stages. */
+ void exitSplitScreen() = 37;
+ /** @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible. */
+ void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) = 38;
+ void startTask(in int taskId, in int stage, in int position, in Bundle options) = 39;
+ void startShortcut(in String packageName, in String shortcutId, in int stage, in int position,
+ in Bundle options, in UserHandle user) = 40;
+ void startIntent(
+ in PendingIntent intent, in Intent fillInIntent, in int stage, in int position,
+ in Bundle options) = 41;
+ void removeFromSideStage(in int taskId) = 42;
+ /**
+ * Sets listener to get task launching callbacks.
+ */
+ void setStartingWindowListener(IStartingWindowListener listener) = 43;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 41840af..937c1df 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -41,18 +41,6 @@
public static final String KEY_EXTRA_INPUT_MONITOR = "extra_input_monitor";
public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
- // See IPip.aidl
- public static final String KEY_EXTRA_SHELL_PIP = "extra_shell_pip";
- // See ISplitScreen.aidl
- public static final String KEY_EXTRA_SHELL_SPLIT_SCREEN = "extra_shell_split_screen";
- // See IOneHanded.aidl
- public static final String KEY_EXTRA_SHELL_ONE_HANDED = "extra_shell_one_handed";
- // See IShellTransitions.aidl
- public static final String KEY_EXTRA_SHELL_SHELL_TRANSITIONS =
- "extra_shell_shell_transitions";
- // See IStartingWindow.aidl
- public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
- "extra_shell_starting_window";
public static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index ed3d5ec..8f79de5 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -34,7 +34,7 @@
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
-import com.android.wm.shell.transition.ShellTransitions;
+import com.android.wm.shell.transition.RemoteTransitions;
import java.util.Optional;
@@ -87,7 +87,7 @@
Builder setShellCommandHandler(Optional<ShellCommandHandler> shellDump);
@BindsInstance
- Builder setTransitions(ShellTransitions t);
+ Builder setTransitions(RemoteTransitions t);
@BindsInstance
Builder setStartingSurface(Optional<StartingSurface> s);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index bbd95b4..1b77d1c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -33,7 +33,7 @@
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
-import com.android.wm.shell.transition.ShellTransitions;
+import com.android.wm.shell.transition.RemoteTransitions;
import java.util.Optional;
@@ -98,7 +98,7 @@
Optional<TaskViewFactory> getTaskViewFactory();
@WMSingleton
- ShellTransitions getTransitions();
+ RemoteTransitions getTransitions();
@WMSingleton
Optional<StartingSurface> getStartingSurface();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index b471659..c3a523f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -35,6 +35,7 @@
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_FORCE_OPAQUE;
import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
@@ -85,6 +86,7 @@
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
import android.view.IWindowManager;
import android.view.InsetsState.InternalInsetsType;
import android.view.KeyEvent;
@@ -213,6 +215,7 @@
private boolean mAllowForceNavBarHandleOpaque;
private boolean mForceNavBarHandleOpaque;
+ private Optional<Long> mHomeButtonLongPressDurationMs;
private boolean mIsCurrentUserSetup;
/** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
@@ -384,6 +387,14 @@
private final Runnable mAutoDim = () -> getBarTransitions().setAutoDim(true);
+ private final Runnable mOnVariableDurationHomeLongClick = () -> {
+ if (onHomeLongClick(mNavigationBarView.getHomeButton().getCurrentView())) {
+ mNavigationBarView.getHomeButton().getCurrentView().performHapticFeedback(
+ HapticFeedbackConstants.LONG_PRESS,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ }
+ };
+
private final ContentObserver mAssistContentObserver = new ContentObserver(
new Handler(Looper.getMainLooper())) {
@Override
@@ -405,6 +416,13 @@
mForceNavBarHandleOpaque = properties.getBoolean(
NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ true);
}
+
+ if (properties.getKeyset().contains(HOME_BUTTON_LONG_PRESS_DURATION_MS)) {
+ mHomeButtonLongPressDurationMs = Optional.of(
+ properties.getLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 0)
+ ).filter(duration -> duration != 0);
+ reconfigureHomeLongClick();
+ }
}
};
@@ -523,6 +541,11 @@
DeviceConfig.NAMESPACE_SYSTEMUI,
NAV_BAR_HANDLE_FORCE_OPAQUE,
/* defaultValue = */ true);
+ mHomeButtonLongPressDurationMs = Optional.of(DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ HOME_BUTTON_LONG_PRESS_DURATION_MS,
+ /* defaultValue = */ 0
+ )).filter(duration -> duration != 0);
DeviceConfig.addOnPropertiesChangedListener(
DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, mOnPropertiesChangedListener);
@@ -782,6 +805,22 @@
}
}
+ private void reconfigureHomeLongClick() {
+ if (mNavigationBarView == null
+ || mNavigationBarView.getHomeButton().getCurrentView() == null) {
+ return;
+ }
+ if (mHomeButtonLongPressDurationMs.isPresent()) {
+ mNavigationBarView.getHomeButton().getCurrentView().setLongClickable(false);
+ mNavigationBarView.getHomeButton().getCurrentView().setHapticFeedbackEnabled(false);
+ mNavigationBarView.getHomeButton().setOnLongClickListener(null);
+ } else {
+ mNavigationBarView.getHomeButton().getCurrentView().setLongClickable(true);
+ mNavigationBarView.getHomeButton().getCurrentView().setHapticFeedbackEnabled(true);
+ mNavigationBarView.getHomeButton().setOnLongClickListener(this::onHomeLongClick);
+ }
+ }
+
private int deltaRotation(int oldRotation, int newRotation) {
int delta = newRotation - oldRotation;
if (delta < 0) delta += 4;
@@ -792,6 +831,7 @@
pw.println("NavigationBar (displayId=" + mDisplayId + "):");
pw.println(" mStartingQuickSwitchRotation=" + mStartingQuickSwitchRotation);
pw.println(" mCurrentRotation=" + mCurrentRotation);
+ pw.println(" mHomeButtonLongPressDurationMs=" + mHomeButtonLongPressDurationMs);
if (mNavigationBarView != null) {
pw.println(" mNavigationBarWindowState="
@@ -1121,7 +1161,8 @@
ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
homeButton.setOnTouchListener(this::onHomeTouch);
- homeButton.setOnLongClickListener(this::onHomeLongClick);
+
+ reconfigureHomeLongClick();
ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
accessibilityButton.setOnClickListener(this::onAccessibilityClick);
@@ -1131,7 +1172,8 @@
updateScreenPinningGestures();
}
- private boolean onHomeTouch(View v, MotionEvent event) {
+ @VisibleForTesting
+ boolean onHomeTouch(View v, MotionEvent event) {
if (mHomeBlockedThisTouch && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
return true;
}
@@ -1151,9 +1193,13 @@
return true;
}
}
+ mHomeButtonLongPressDurationMs.ifPresent(longPressDuration -> {
+ mHandler.postDelayed(mOnVariableDurationHomeLongClick, longPressDuration);
+ });
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+ mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
mStatusBarLazy.get().awakenDreams();
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index 14a3fc0..1a17e61 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -416,7 +416,6 @@
}
} else {
state.icon = ResourceIcon.get(cb.mWifiSignalIconId);
- state.label = r.getString(R.string.quick_settings_airplane_safe_label);
}
} else if (cb.mNoDefaultNetwork && cb.mNoNetworksAvailable) {
state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
@@ -480,9 +479,6 @@
state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available);
state.secondaryLabel = r.getString(R.string.quick_settings_networks_available);
} else {
- if (cb.mAirplaneModeEnabled) {
- state.label = r.getString(R.string.quick_settings_airplane_safe_label);
- }
state.icon = new SignalIcon(cb.mMobileSignalIconId);
state.secondaryLabel = appendMobileDataType(cb.mDataSubscriptionName,
getMobileDataContentName(cb));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index b0a3f43..8951605 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -25,11 +25,6 @@
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
@@ -40,12 +35,15 @@
import android.annotation.FloatRange;
import android.app.ActivityTaskManager;
+import android.app.PendingIntent;
+import android.app.PictureInPictureParams;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -59,12 +57,14 @@
import android.os.PatternMatcher;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.ArraySet;
import android.util.Log;
import android.view.InputMonitor;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.accessibility.AccessibilityManager;
+import android.window.IRemoteTransition;
import androidx.annotation.NonNull;
@@ -83,11 +83,15 @@
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.shared.recents.IOverviewProxy;
+import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
+import com.android.systemui.shared.recents.ISplitScreenListener;
+import com.android.systemui.shared.recents.IStartingWindowListener;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.RemoteTransitionCompat;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -99,7 +103,7 @@
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
-import com.android.wm.shell.transition.ShellTransitions;
+import com.android.wm.shell.transition.RemoteTransitions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -107,6 +111,7 @@
import java.util.List;
import java.util.Optional;
import java.util.function.BiConsumer;
+import java.util.function.Consumer;
import javax.inject.Inject;
@@ -146,11 +151,12 @@
private final ScreenshotHelper mScreenshotHelper;
private final Optional<OneHanded> mOneHandedOptional;
private final CommandQueue mCommandQueue;
- private final ShellTransitions mShellTransitions;
+ private final RemoteTransitions mShellTransitions;
private final Optional<StartingSurface> mStartingSurface;
private Region mActiveNavBarRegion;
+ private IPinnedStackAnimationListener mIPinnedStackAnimationListener;
private IOverviewProxy mOverviewProxy;
private int mConnectionBackoffAttempts;
private boolean mBound;
@@ -163,6 +169,8 @@
private float mWindowCornerRadius;
private boolean mSupportsRoundedCornersOnWindows;
private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
+ private final ArraySet<IRemoteTransition> mRemoteTransitions = new ArraySet<>();
+ private IStartingWindowListener mIStartingWindowListener;
@VisibleForTesting
public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -375,6 +383,20 @@
}
@Override
+ public void setShelfHeight(boolean visible, int shelfHeight) {
+ if (!verifyCaller("setShelfHeight")) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mPipOptional.ifPresent(
+ pip -> pip.setShelfHeight(visible, shelfHeight));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen,
Insets visibleInsets, int taskId) {
// Deprecated
@@ -402,6 +424,36 @@
}
@Override
+ public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
+ if (!verifyCaller("setPinnedStackAnimationListener")) {
+ return;
+ }
+ mIPinnedStackAnimationListener = listener;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mPipOptional.ifPresent(
+ pip -> pip.setPinnedStackAnimationListener(mPinnedStackAnimationCallback));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setStartingWindowListener(IStartingWindowListener listener) {
+ if (!verifyCaller("setStartingWindowListener")) {
+ return;
+ }
+ mIStartingWindowListener = listener;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mStartingSurface.ifPresent(s ->
+ s.setStartingWindowListener(mStartingWindowListener));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {
if (!verifyCaller("onQuickSwitchToNewTask")) {
return;
@@ -415,6 +467,32 @@
}
@Override
+ public void startOneHandedMode() {
+ if (!verifyCaller("startOneHandedMode")) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mOneHandedOptional.ifPresent(oneHanded -> oneHanded.startOneHanded());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void stopOneHandedMode() {
+ if (!verifyCaller("stopOneHandedMode")) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mOneHandedOptional.ifPresent(oneHanded -> oneHanded.stopOneHanded());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
Insets visibleInsets, Task.TaskKey task) {
mScreenshotHelper.provideScreenshot(
@@ -442,6 +520,190 @@
}
}
+ @Override
+ public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
+ PictureInPictureParams pictureInPictureParams,
+ int launcherRotation, int shelfHeight) {
+ if (!verifyCaller("startSwipePipToHome")) {
+ return null;
+ }
+ final long binderToken = Binder.clearCallingIdentity();
+ try {
+ return mPipOptional.map(pip ->
+ pip.startSwipePipToHome(componentName, activityInfo,
+ pictureInPictureParams, launcherRotation, shelfHeight))
+ .orElse(null);
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
+ }
+ }
+
+ @Override
+ public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+ if (!verifyCaller("stopSwipePipToHome")) {
+ return;
+ }
+ final long binderToken = Binder.clearCallingIdentity();
+ try {
+ mPipOptional.ifPresent(pip -> pip.stopSwipePipToHome(
+ componentName, destinationBounds));
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
+ }
+ }
+
+ @Override
+ public void registerRemoteTransition(RemoteTransitionCompat remoteTransition) {
+ if (!verifyCaller("registerRemoteTransition")) return;
+ final long binderToken = Binder.clearCallingIdentity();
+ try {
+ mRemoteTransitions.add(remoteTransition.getTransition());
+ mShellTransitions.registerRemote(
+ remoteTransition.getFilter(), remoteTransition.getTransition());
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
+ }
+ }
+
+ @Override
+ public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) {
+ if (!verifyCaller("registerRemoteTransition")) return;
+ final long binderToken = Binder.clearCallingIdentity();
+ try {
+ mRemoteTransitions.remove(remoteTransition.getTransition());
+ mShellTransitions.unregisterRemote(remoteTransition.getTransition());
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
+ }
+ }
+
+ @Override
+ public void registerSplitScreenListener(ISplitScreenListener listener) {
+ if (!verifyCaller("registerSplitScreenListener")) {
+ return;
+ }
+ mISplitScreenListener = listener;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mSplitScreenOptional.ifPresent(
+ s -> s.registerSplitScreenListener(mSplitScreenListener));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void unregisterSplitScreenListener(ISplitScreenListener listener) {
+ if (!verifyCaller("unregisterSplitScreenListener")) {
+ return;
+ }
+ mISplitScreenListener = null;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mSplitScreenOptional.ifPresent(
+ s -> s.unregisterSplitScreenListener(mSplitScreenListener));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setSideStageVisibility(boolean visible) {
+ if (!verifyCaller("setSideStageVisibility")) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mSplitScreenOptional.ifPresent(s -> s.setSideStageVisibility(visible));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void exitSplitScreen() {
+ if (!verifyCaller("exitSplitScreen")) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mSplitScreenOptional.ifPresent(s -> s.exitSplitScreen());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
+ if (!verifyCaller("exitSplitScreenOnHide")) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mSplitScreenOptional.ifPresent(s -> s.exitSplitScreenOnHide(exitSplitScreenOnHide));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void startTask(int taskId, int stage, int position, Bundle options) {
+ if (!verifyCaller("startTask")) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mSplitScreenOptional.ifPresent(
+ s -> s.startTask(taskId, stage, position, options));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void startShortcut(String packageName, String shortcutId, int stage, int position,
+ Bundle options, UserHandle user) {
+ if (!verifyCaller("startShortcut")) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mSplitScreenOptional.ifPresent(s ->
+ s.startShortcut(packageName, shortcutId, stage, position, options, user));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void startIntent(PendingIntent intent, Intent fillInIntent,
+ int stage, int position, Bundle options) {
+ if (!verifyCaller("startIntent")) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mSplitScreenOptional.ifPresent(s ->
+ s.startIntent(intent, mContext, fillInIntent, stage, position, options));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void removeFromSideStage(int taskId) {
+ if (!verifyCaller("removeFromSideStage")) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mSplitScreenOptional.ifPresent(
+ s -> s.removeFromSideStage(taskId));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private boolean verifyCaller(String reason) {
final int callerId = Binder.getCallingUserHandle().getIdentifier();
if (callerId != mCurrentBoundedUserId) {
@@ -495,22 +757,6 @@
params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
-
- mPipOptional.ifPresent((pip) -> params.putBinder(
- KEY_EXTRA_SHELL_PIP,
- pip.createExternalInterface().asBinder()));
- mSplitScreenOptional.ifPresent((splitscreen) -> params.putBinder(
- KEY_EXTRA_SHELL_SPLIT_SCREEN,
- splitscreen.createExternalInterface().asBinder()));
- mOneHandedOptional.ifPresent((onehanded) -> params.putBinder(
- KEY_EXTRA_SHELL_ONE_HANDED,
- onehanded.createExternalInterface().asBinder()));
- params.putBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS,
- mShellTransitions.createExternalInterface().asBinder());
- mStartingSurface.ifPresent((startingwindow) -> params.putBinder(
- KEY_EXTRA_SHELL_STARTING_WINDOW,
- startingwindow.createExternalInterface().asBinder()));
-
try {
mOverviewProxy.onInitialize(params);
} catch (RemoteException e) {
@@ -550,11 +796,42 @@
private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged;
private final BiConsumer<Rect, Rect> mSplitScreenBoundsChangeListener =
this::notifySplitScreenBoundsChanged;
+ private final Consumer<Boolean> mPinnedStackAnimationCallback =
+ this::notifyPinnedStackAnimationStarted;
+
+ private final BiConsumer<Integer, Integer> mStartingWindowListener =
+ this::notifyTaskLaunching;
// This is the death handler for the binder from the launcher service
private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
= this::cleanupAfterDeath;
+ private ISplitScreenListener mISplitScreenListener;
+ private final SplitScreen.SplitScreenListener mSplitScreenListener =
+ new SplitScreen.SplitScreenListener() {
+ @Override
+ public void onStagePositionChanged(int stage, int position) {
+ try {
+ if (mISplitScreenListener != null) {
+ mISplitScreenListener.onStagePositionChanged(stage, position);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG_OPS, "onStagePositionChanged", e);
+ }
+ }
+
+ @Override
+ public void onTaskStageChanged(int taskId, int stage, boolean visible) {
+ try {
+ if (mISplitScreenListener != null) {
+ mISplitScreenListener.onTaskStageChanged(taskId, stage, visible);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG_OPS, "onTaskStageChanged", e);
+ }
+ }
+ };
+
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyService(Context context, CommandQueue commandQueue,
@@ -567,7 +844,7 @@
Optional<Lazy<StatusBar>> statusBarOptionalLazy,
Optional<OneHanded> oneHandedOptional,
BroadcastDispatcher broadcastDispatcher,
- ShellTransitions shellTransitions,
+ RemoteTransitions shellTransitions,
Optional<StartingSurface> startingSurface) {
super(broadcastDispatcher);
mContext = context;
@@ -684,6 +961,29 @@
}
}
+ private void notifyPinnedStackAnimationStarted(Boolean isAnimationStarted) {
+ if (mIPinnedStackAnimationListener == null) {
+ return;
+ }
+ try {
+ mIPinnedStackAnimationListener.onPinnedStackAnimationStarted();
+ } catch (RemoteException e) {
+ Log.e(TAG_OPS, "Failed to call onPinnedStackAnimationStarted()", e);
+ }
+ }
+
+ private void notifyTaskLaunching(int taskId, int supportedType) {
+ if (mIStartingWindowListener == null) {
+ return;
+ }
+
+ try {
+ mIStartingWindowListener.onTaskLaunching(taskId, supportedType);
+ } catch (RemoteException e) {
+ Log.e(TAG_OPS, "Failed to call notifyTaskLaunching()", e);
+ }
+ }
+
private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
boolean bouncerShowing) {
mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
@@ -727,6 +1027,12 @@
// Clean up the minimized state if launcher dies
mLegacySplitScreenOptional.ifPresent(
splitScreen -> splitScreen.setMinimized(false));
+
+ // Clean up any registered remote transitions
+ for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) {
+ mShellTransitions.unregisterRemote(mRemoteTransitions.valueAt(i));
+ }
+ mRemoteTransitions.clear();
}
public void startConnectionToCurrentUser() {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index ddfa63a..3f4ec85 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -81,7 +81,7 @@
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.startingsurface.StartingWindowController;
-import com.android.wm.shell.transition.ShellTransitions;
+import com.android.wm.shell.transition.RemoteTransitions;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -399,8 +399,8 @@
@WMSingleton
@Provides
- static ShellTransitions provideRemoteTransitions(Transitions transitions) {
- return transitions.asRemoteTransitions();
+ static RemoteTransitions provideRemoteTransitions(Transitions transitions) {
+ return Transitions.asRemoteTransitions(transitions);
}
@WMSingleton
@@ -509,33 +509,27 @@
@WMSingleton
@Provides
- static ShellInit provideShellInit(ShellInitImpl impl) {
- return impl.asShellInit();
- }
-
- @WMSingleton
- @Provides
- static ShellInitImpl provideShellInitImpl(DisplayImeController displayImeController,
+ static ShellInit provideShellInit(DisplayImeController displayImeController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
+ Optional<StartingSurface> startingSurface,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
- StartingWindowController startingWindow,
@ShellMainThread ShellExecutor mainExecutor) {
- return new ShellInitImpl(displayImeController,
+ return ShellInitImpl.create(displayImeController,
dragAndDropController,
shellTaskOrganizer,
legacySplitScreenOptional,
splitScreenOptional,
appPairsOptional,
+ startingSurface,
pipTouchHandlerOptional,
fullscreenTaskListener,
transitions,
- startingWindow,
mainExecutor);
}
@@ -545,13 +539,7 @@
*/
@WMSingleton
@Provides
- static Optional<ShellCommandHandler> provideShellCommandHandler(ShellCommandHandlerImpl impl) {
- return Optional.of(impl.asShellCommandHandler());
- }
-
- @WMSingleton
- @Provides
- static ShellCommandHandlerImpl provideShellCommandHandlerImpl(
+ static Optional<ShellCommandHandler> provideShellCommandHandler(
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
@@ -560,8 +548,8 @@
Optional<HideDisplayCutoutController> hideDisplayCutout,
Optional<AppPairsController> appPairsOptional,
@ShellMainThread ShellExecutor mainExecutor) {
- return new ShellCommandHandlerImpl(shellTaskOrganizer,
+ return Optional.of(ShellCommandHandlerImpl.create(shellTaskOrganizer,
legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional,
- hideDisplayCutout, appPairsOptional, mainExecutor);
+ hideDisplayCutout, appPairsOptional, mainExecutor));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 2b76f1c..22c553b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -23,6 +23,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS;
import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS;
import static org.junit.Assert.assertEquals;
@@ -31,6 +32,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -44,12 +46,16 @@
import android.hardware.display.DisplayManagerGlobal;
import android.os.Handler;
import android.os.Looper;
+import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.WindowMetrics;
import android.view.accessibility.AccessibilityManager;
@@ -79,6 +85,7 @@
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -101,6 +108,7 @@
private OverviewProxyService mOverviewProxyService;
private CommandQueue mCommandQueue;
private SysUiState mMockSysUiState;
+ @Mock
private Handler mHandler;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@@ -124,12 +132,17 @@
mDependency.injectMockDependency(NavigationBarController.class);
mOverviewProxyService = mDependency.injectMockDependency(OverviewProxyService.class);
TestableLooper.get(this).runWithLooper(() -> {
- mHandler = new Handler();
mNavigationBar = createNavBar(mContext);
mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal);
});
}
+ @After
+ public void tearDown() throws Exception {
+ DeviceConfig.resetToDefaults(
+ Settings.RESET_MODE_PACKAGE_DEFAULTS, DeviceConfig.NAMESPACE_SYSTEMUI);
+ }
+
private void setupSysuiDependency() {
Display display = new Display(DisplayManagerGlobal.getInstance(), EXTERNAL_DISPLAY_ID,
new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
@@ -163,6 +176,32 @@
}
@Test
+ public void testHomeLongPressWithCustomDuration() throws Exception {
+ DeviceConfig.setProperties(
+ new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_SYSTEMUI)
+ .setLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 100)
+ .build());
+ mNavigationBar.onViewAttachedToWindow(mNavigationBar.createView(null));
+
+ mNavigationBar.onHomeTouch(mNavigationBar.getView(), MotionEvent.obtain(
+ /*downTime=*/SystemClock.uptimeMillis(),
+ /*eventTime=*/SystemClock.uptimeMillis(),
+ /*action=*/MotionEvent.ACTION_DOWN,
+ 0, 0, 0
+ ));
+ verify(mHandler, times(1)).postDelayed(any(), eq(100L));
+
+ mNavigationBar.onHomeTouch(mNavigationBar.getView(), MotionEvent.obtain(
+ /*downTime=*/SystemClock.uptimeMillis(),
+ /*eventTime=*/SystemClock.uptimeMillis(),
+ /*action=*/MotionEvent.ACTION_UP,
+ 0, 0, 0
+ ));
+
+ verify(mHandler, times(1)).removeCallbacks(any());
+ }
+
+ @Test
public void testRegisteredWithDispatcher() {
mNavigationBar.onViewAttachedToWindow(mNavigationBar.createView(null));
verify(mBroadcastDispatcher).registerReceiverWithHandler(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
new file mode 100644
index 0000000..25104b8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.systemui.recents;
+
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.testing.TestableLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.navigationbar.NavigationBarController;
+import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.startingsurface.StartingSurface;
+import com.android.wm.shell.transition.RemoteTransitions;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Optional;
+
+import dagger.Lazy;
+
+/**
+ * Unit tests for {@link com.android.systemui.recents.OverviewProxyService}
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class OverviewProxyServiceTest extends SysuiTestCase {
+ private OverviewProxyService mSpiedOverviewProxyService;
+ private TestableContext mSpiedContext;
+
+ @Mock private BroadcastDispatcher mMockBroadcastDispatcher;
+ @Mock private CommandQueue mMockCommandQueue;
+ @Mock private Lazy<NavigationBarController> mMockNavBarControllerLazy;
+ @Mock private IPinnedStackAnimationListener mMockPinnedStackAnimationListener;
+ @Mock private NavigationModeController mMockNavModeController;
+ @Mock private NotificationShadeWindowController mMockStatusBarWinController;
+ @Mock private Optional<Pip> mMockPipOptional;
+ @Mock private Optional<LegacySplitScreen> mMockLegacySplitScreenOptional;
+ @Mock private Optional<SplitScreen> mMockSplitScreenOptional;
+ @Mock private Optional<Lazy<StatusBar>> mMockStatusBarOptionalLazy;
+ @Mock private Optional<com.android.wm.shell.onehanded.OneHanded> mMockOneHandedOptional;
+ @Mock private PackageManager mPackageManager;
+ @Mock private SysUiState mMockSysUiState;
+ @Mock private RemoteTransitions mMockTransitions;
+ @Mock private Optional<StartingSurface> mStartingSurface;
+
+ @Before
+ public void setUp() throws RemoteException {
+ MockitoAnnotations.initMocks(this);
+
+ mSpiedContext = spy(mContext);
+
+ when(mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false);
+ when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager);
+
+ mSpiedOverviewProxyService = spy(new OverviewProxyService(mSpiedContext, mMockCommandQueue,
+ mMockNavBarControllerLazy, mMockNavModeController, mMockStatusBarWinController,
+ mMockSysUiState, mMockPipOptional, mMockLegacySplitScreenOptional,
+ mMockSplitScreenOptional, mMockStatusBarOptionalLazy, mMockOneHandedOptional,
+ mMockBroadcastDispatcher, mMockTransitions, mStartingSurface));
+ }
+
+ @Test
+ public void testNonPipDevice_shouldNotNotifySwipeToHomeFinished() throws RemoteException {
+ mSpiedOverviewProxyService.mSysUiProxy.notifySwipeToHomeFinished();
+
+ verify(mMockPipOptional, never()).ifPresent(any());
+ }
+
+ @Test
+ public void testNonPipDevice_shouldNotSetPinnedStackAnimationListener() throws RemoteException {
+ mSpiedOverviewProxyService.mSysUiProxy.setPinnedStackAnimationListener(
+ mMockPinnedStackAnimationListener);
+
+ verify(mMockPipOptional, never()).ifPresent(any());
+ }
+
+ @Test
+ public void testNonPipDevice_shouldNotSetShelfHeight() throws RemoteException {
+ mSpiedOverviewProxyService.mSysUiProxy.setShelfHeight(true /* visible */,
+ 100 /* shelfHeight */);
+
+ verify(mMockPipOptional, never()).ifPresent(any());
+ }
+}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index b00689b..0fe874c 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -81,10 +81,19 @@
out: ["services.core.protolog.json"],
}
+genrule {
+ name: "statslog-art-java-gen",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --java $(out) --module art" +
+ " --javaPackage com.android.internal.art --javaClass ArtStatsLog --worksource",
+ out: ["com/android/internal/art/ArtStatsLog.java"],
+}
+
java_library_static {
name: "services.core.unboosted",
defaults: ["platform_service_defaults"],
srcs: [
+ ":statslog-art-java-gen",
":services.core-sources",
":services.core.protologsrc",
":dumpstate_aidl",
diff --git a/services/core/java/com/android/server/ContextHubSystemService.java b/services/core/java/com/android/server/ContextHubSystemService.java
index a353519..96ff900 100644
--- a/services/core/java/com/android/server/ContextHubSystemService.java
+++ b/services/core/java/com/android/server/ContextHubSystemService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.util.Log;
@@ -51,4 +53,9 @@
publishBinderService(Context.CONTEXTHUB_SERVICE, mContextHubService);
}
}
+
+ @Override
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ mContextHubService.onUserChanged();
+ }
}
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index dde45c4..c44089b 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -17,13 +17,16 @@
package com.android.server.location.contexthub;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManagerInternal;
import android.hardware.contexthub.V1_0.AsyncEventType;
import android.hardware.contexthub.V1_0.ContextHub;
import android.hardware.contexthub.V1_0.ContextHubMsg;
@@ -59,6 +62,7 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.DumpUtils;
+import com.android.server.LocalServices;
import com.android.server.location.ContextHubServiceProto;
import java.io.FileDescriptor;
@@ -127,6 +131,8 @@
// Lock object for sendWifiSettingUpdate()
private final Object mSendWifiSettingUpdateLock = new Object();
+ private final SensorPrivacyManagerInternal mSensorPrivacyManagerInternal;
+
/**
* Class extending the callback to register with a Context Hub.
*/
@@ -186,6 +192,7 @@
if (mContextHubWrapper == null) {
mTransactionManager = null;
mClientManager = null;
+ mSensorPrivacyManagerInternal = null;
mDefaultClientMap = Collections.emptyMap();
mContextHubIdToInfoMap = Collections.emptyMap();
mSupportedContextHubPerms = Collections.emptyList();
@@ -208,6 +215,8 @@
mClientManager = new ContextHubClientManager(mContext, mContextHubWrapper);
mTransactionManager = new ContextHubTransactionManager(
mContextHubWrapper.getHub(), mClientManager, mNanoAppStateManager);
+ mSensorPrivacyManagerInternal =
+ LocalServices.getService(SensorPrivacyManagerInternal.class);
HashMap<Integer, IContextHubClient> defaultClientMap = new HashMap<>();
for (int contextHubId : mContextHubIdToInfoMap.keySet()) {
@@ -284,18 +293,16 @@
}
if (mContextHubWrapper.supportsMicrophoneDisableSettingNotifications()) {
- sendMicrophoneDisableSettingUpdate();
+ sendMicrophoneDisableSettingUpdateForCurrentUser();
- SensorPrivacyManager.OnSensorPrivacyChangedListener listener =
- new SensorPrivacyManager.OnSensorPrivacyChangedListener() {
- @Override
- public void onSensorPrivacyChanged(boolean enabled) {
- sendMicrophoneDisableSettingUpdate();
- }
- };
- SensorPrivacyManager manager = SensorPrivacyManager.getInstance(mContext);
- manager.addSensorPrivacyListener(
- SensorPrivacyManager.Sensors.MICROPHONE, listener);
+ mSensorPrivacyManagerInternal.addSensorPrivacyListenerForAllUsers(
+ SensorPrivacyManager.Sensors.MICROPHONE, (userId, enabled) -> {
+ if (userId == getCurrentUserId()) {
+ Log.d(TAG, "User: " + userId + " enabled: " + enabled);
+ sendMicrophoneDisableSettingUpdate(enabled);
+ }
+ });
+
}
}
@@ -1074,19 +1081,48 @@
}
/**
- * Obtains the latest microphone disable setting value and notifies the
- * Context Hub.
+ * Notifies a microphone disable settings change to the Context Hub.
*/
- private void sendMicrophoneDisableSettingUpdate() {
- SensorPrivacyManager manager = SensorPrivacyManager.getInstance(mContext);
- boolean disabled = manager.isSensorPrivacyEnabled(
- SensorPrivacyManager.Sensors.MICROPHONE);
- Log.d(TAG, "Mic Disabled Setting: " + disabled);
- mContextHubWrapper.onMicrophoneDisableSettingChanged(disabled);
+ private void sendMicrophoneDisableSettingUpdate(boolean enabled) {
+ Log.d(TAG, "Mic Disabled Setting: " + enabled);
+ mContextHubWrapper.onMicrophoneDisableSettingChanged(enabled);
+ }
+
+ /**
+ * Obtains the latest microphone disabled setting for the current user
+ * and notifies the Context Hub.
+ */
+ private void sendMicrophoneDisableSettingUpdateForCurrentUser() {
+ boolean isEnabled = mSensorPrivacyManagerInternal.isSensorPrivacyEnabled(
+ getCurrentUserId(), SensorPrivacyManager.Sensors.MICROPHONE);
+ sendMicrophoneDisableSettingUpdate(isEnabled);
}
private String getCallingPackageName() {
return mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
}
+
+ private int getCurrentUserId() {
+ final long id = Binder.clearCallingIdentity();
+ try {
+ UserInfo currentUser = ActivityManager.getService().getCurrentUser();
+ return currentUser.id;
+ } catch (RemoteException e) {
+ // Activity manager not running, nothing we can do - assume user 0.
+ } finally {
+ Binder.restoreCallingIdentity(id);
+ }
+ return UserHandle.USER_SYSTEM;
+ }
+
+ /**
+ * Send a microphone disable settings update whenever the foreground user changes.
+ * We always send a settings update regardless of the previous state for the same user
+ * since the CHRE framework is expected to handle repeated identical setting update.
+ */
+ public void onUserChanged() {
+ Log.d(TAG, "User changed to id: " + getCurrentUserId());
+ sendMicrophoneDisableSettingUpdateForCurrentUser();
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 0a443f3..7aaab0c 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -51,6 +51,7 @@
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
import android.os.storage.StorageManager;
@@ -62,6 +63,8 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.ArtManagerService;
+import com.android.server.pm.dex.ArtStatsLogUtils;
+import com.android.server.pm.dex.ArtStatsLogUtils.ArtStatsLogger;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.DexoptUtils;
@@ -99,6 +102,8 @@
private final PowerManager.WakeLock mDexoptWakeLock;
private volatile boolean mSystemReady;
+ private final ArtStatsLogger mArtStatsLogger = new ArtStatsLogger();
+
PackageDexOptimizer(Installer installer, Object installLock, Context context,
String wakeLockTag) {
this.mInstaller = installer;
@@ -252,6 +257,28 @@
profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid,
packageStats, options.isDowngrade(), profileName, dexMetadataPath,
options.getCompilationReason());
+
+ // Only report metrics for base apk for now.
+ // TODO: add ISA and APK type to metrics.
+ if (pkg.getBaseApkPath().equals(path)) {
+ Trace.traceBegin(Trace.TRACE_TAG_PACKAGE_MANAGER, "dex2oat-metrics");
+ try {
+ long sessionId = Math.randomLongInternal();
+ ArtStatsLogUtils.writeStatsLog(
+ mArtStatsLogger,
+ sessionId,
+ path,
+ compilerFilter,
+ sharedGid,
+ packageStats.getCompileTime(path),
+ dexMetadataPath,
+ options.getCompilationReason(),
+ newResult);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
// The end result is:
// - FAILED if any path failed,
// - PERFORMED if at least one path needed compilation,
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
new file mode 100644
index 0000000..3b77c39
--- /dev/null
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2021 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.server.pm.dex;
+
+import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
+import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
+import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
+import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
+import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
+
+import android.util.jar.StrictJarFile;
+import android.util.Slog;
+
+import com.android.internal.art.ArtStatsLog;
+import com.android.server.pm.PackageManagerService;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+
+/** Utils class to report ART metrics to statsd. */
+public class ArtStatsLogUtils {
+ private static final String TAG = ArtStatsLogUtils.class.getSimpleName();
+ private static final String PROFILE_DEX_METADATA = "primary.prof";
+ private static final String VDEX_DEX_METADATA = "primary.vdex";
+
+
+ private static final int ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY =
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
+ private static final int ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED =
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
+ private static final int ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED =
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
+
+ private static final int ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK =
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
+ private static final int ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK =
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
+
+ private static final Map<Integer, Integer> COMPILATION_REASON_MAP = new HashMap();
+
+ static {
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_UNKNOWN, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_FIRST_BOOT, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_FIRST_BOOT);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_BOOT_AFTER_OTA, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BOOT);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_POST_BOOT, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_POST_BOOT);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_FAST, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_FAST);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_SECONDARY,
+ ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED,
+ ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED,
+ ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_BACKGROUND_DEXOPT, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BG_DEXOPT);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_AB_OTA, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_AB_OTA);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE,
+ ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INACTIVE);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_SHARED,
+ ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_SHARED);
+ }
+
+ private static final Map<String, Integer> COMPILE_FILTER_MAP = new HashMap();
+
+ static {
+ COMPILE_FILTER_MAP.put("error", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ERROR);
+ COMPILE_FILTER_MAP.put("unknown", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN);
+ COMPILE_FILTER_MAP.put("assume-verified", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ASSUMED_VERIFIED);
+ COMPILE_FILTER_MAP.put("extract", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EXTRACT);
+ COMPILE_FILTER_MAP.put("verify", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_VERIFY);
+ COMPILE_FILTER_MAP.put("quicken", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_QUICKEN);
+ COMPILE_FILTER_MAP.put("space-profile", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE_PROFILE);
+ COMPILE_FILTER_MAP.put("space", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE);
+ COMPILE_FILTER_MAP.put("speed-profile", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED_PROFILE);
+ COMPILE_FILTER_MAP.put("speed", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED);
+ COMPILE_FILTER_MAP.put("everything-profile", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING_PROFILE);
+ COMPILE_FILTER_MAP.put("everything", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING);
+ COMPILE_FILTER_MAP.put("run-from-apk", ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK);
+ COMPILE_FILTER_MAP.put("run-from-apk-fallback",
+ ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK);
+ COMPILE_FILTER_MAP.put("run-from-vdex-fallback",
+ ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK);
+ }
+
+ public static void writeStatsLog(
+ ArtStatsLogger logger,
+ long sessionId,
+ String path,
+ String compilerFilter,
+ int uid,
+ long compileTime,
+ String dexMetadataPath,
+ int compilationReason,
+ int result) {
+ int dexMetadataType = getDexMetadataType(dexMetadataPath);
+ logger.write(
+ sessionId,
+ uid,
+ compilationReason,
+ compilerFilter,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE,
+ result,
+ dexMetadataType);
+ logger.write(
+ sessionId,
+ uid,
+ compilationReason,
+ compilerFilter,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES,
+ getDexBytes(path),
+ dexMetadataType);
+ logger.write(
+ sessionId,
+ uid,
+ compilationReason,
+ compilerFilter,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
+ compileTime,
+ dexMetadataType);
+ }
+
+ private static long getDexBytes(String apkPath) {
+ StrictJarFile jarFile = null;
+ long dexBytes = 0;
+ try {
+ jarFile = new StrictJarFile(apkPath,
+ /*verify=*/ false,
+ /*signatureSchemeRollbackProtectionsEnforced=*/ false);
+ Iterator<ZipEntry> it = jarFile.iterator();
+ while (it.hasNext()) {
+ ZipEntry entry = it.next();
+ if (entry.getName().matches("classes(\\d)*[.]dex")) {
+ dexBytes += entry.getSize();
+ }
+ }
+ return dexBytes;
+ } catch (IOException ignore) {
+ Slog.e(TAG, "Error when parsing APK " + apkPath);
+ return -1L;
+ } finally {
+ try {
+ if (jarFile != null) {
+ jarFile.close();
+ }
+ } catch (IOException ignore) {
+ }
+ }
+ }
+
+ private static int getDexMetadataType(String dexMetadataPath) {
+ if (dexMetadataPath == null) {
+ return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__NONE_DEX_METADATA;
+ }
+ StrictJarFile jarFile = null;
+ try {
+ jarFile = new StrictJarFile(dexMetadataPath,
+ /*verify=*/ false,
+ /*signatureSchemeRollbackProtectionsEnforced=*/false);
+ boolean hasProfile = findFileName(jarFile, PROFILE_DEX_METADATA);
+ boolean hasVdex = findFileName(jarFile, VDEX_DEX_METADATA);
+ if (hasProfile && hasVdex) {
+ return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__PROFILE_AND_VDEX;
+ } else if (hasProfile) {
+ return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__PROFILE;
+ } else if (hasVdex) {
+ return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__VDEX;
+ } else {
+ return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__UNKNOWN_DEX_METADATA;
+ }
+ } catch (IOException ignore) {
+ Slog.e(TAG, "Error when parsing dex metadata " + dexMetadataPath);
+ return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ERROR_DEX_METADATA;
+ } finally {
+ try {
+ if (jarFile != null) {
+ jarFile.close();
+ }
+ } catch (IOException ignore) {
+ }
+ }
+ }
+
+ private static boolean findFileName(StrictJarFile jarFile, String filename) throws IOException {
+ Iterator<ZipEntry> it = jarFile.iterator();
+ while (it.hasNext()) {
+ ZipEntry entry = it.next();
+ if (entry.getName().equals(filename)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static class ArtStatsLogger {
+ public void write(
+ long sessionId,
+ int uid,
+ int compilationReason,
+ String compilerFilter,
+ int kind,
+ long value,
+ int dexMetadataType) {
+ ArtStatsLog.write(
+ ArtStatsLog.ART_DATUM_REPORTED,
+ sessionId,
+ uid,
+ COMPILE_FILTER_MAP.getOrDefault(compilerFilter, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN),
+ COMPILATION_REASON_MAP.getOrDefault(compilationReason, ArtStatsLog.
+ ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN),
+ /*timestamp_millis=*/ 0L,
+ ArtStatsLog.ART_DATUM_REPORTED__THREAD_TYPE__ART_THREAD_MAIN,
+ kind,
+ value,
+ dexMetadataType);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index e3ccb75..27bf8a13 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -737,10 +737,12 @@
}
}
if (locationExtraPackageNames != null) {
- // Also grant location permission to location extra packages.
+ // Also grant location and activity recognition permission to location extra packages.
for (String packageName : locationExtraPackageNames) {
grantPermissionsToSystemPackage(pm, packageName, userId,
ALWAYS_LOCATION_PERMISSIONS);
+ grantSystemFixedPermissionsToSystemPackage(pm, packageName, userId,
+ ACTIVITY_RECOGNITION_PERMISSIONS);
}
}
diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java
index 1e8b8a5..4cc369f 100644
--- a/services/core/java/com/android/server/wm/SeamlessRotator.java
+++ b/services/core/java/com/android/server/wm/SeamlessRotator.java
@@ -102,6 +102,10 @@
* window in the new orientation.
*/
void finish(Transaction t, WindowContainer win) {
+ if (win.mSurfaceControl == null || !win.mSurfaceControl.isValid()) {
+ return;
+ }
+
mTransform.reset();
t.setMatrix(win.mSurfaceControl, mTransform, mFloat9);
t.setPosition(win.mSurfaceControl, win.mLastSurfacePosition.x, win.mLastSurfacePosition.y);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1a2eee0..ac2281a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8817,6 +8817,9 @@
return null;
}
final ComponentName supervisorComponent = ComponentName.unflattenFromString(supervisor);
+ if (supervisorComponent == null) {
+ return null;
+ }
if (supervisorComponent.equals(doComponent) || supervisorComponent.equals(
poComponent)) {
return supervisorComponent;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
new file mode 100644
index 0000000..3ab3448
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2021 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.server.pm.dex;
+
+import static org.mockito.Mockito.inOrder;
+
+import com.android.internal.art.ArtStatsLog;
+import com.android.server.pm.dex.ArtStatsLogUtils.ArtStatsLogger;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.InOrder;
+import org.mockito.MockitoAnnotations;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Unit tests for {@link com.android.server.pm.dex.ArtStatsLogUtils}.
+ *
+ * Run with "atest ArtStatsLogUtilsTest".
+ */
+@RunWith(JUnit4.class)
+public final class ArtStatsLogUtilsTest {
+ private static final String TAG = ArtStatsLogUtilsTest.class.getSimpleName();
+ private static final String COMPILER_FILTER = "space-profile";
+ private static final String PROFILE_DEX_METADATA = "primary.prof";
+ private static final String VDEX_DEX_METADATA = "primary.vdex";
+ private static final byte[] DEX_CONTENT = "dexData".getBytes();
+ private static final int COMPILATION_REASON = 1;
+ private static final int RESULT_CODE = 222;
+ private static final int UID = 111;
+ private static final long COMPILE_TIME = 333L;
+ private static final long SESSION_ID = 444L;
+
+ @Mock
+ ArtStatsLogger mockLogger;
+
+ private static Path TEST_DIR;
+ private static Path DEX;
+ private static Path NON_DEX;
+
+ @BeforeClass
+ public static void setUpAll() throws IOException {
+ TEST_DIR = Files.createTempDirectory(null);
+ DEX = Files.createFile(TEST_DIR.resolve("classes.dex"));
+ NON_DEX = Files.createFile(TEST_DIR.resolve("test.dex"));
+ Files.write(DEX, DEX_CONTENT);
+ Files.write(NON_DEX, "empty".getBytes());
+ }
+
+ @AfterClass
+ public static void tearnDownAll() {
+ deleteSliently(DEX);
+ deleteSliently(NON_DEX);
+ deleteSliently(TEST_DIR);
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testProfileAndVdexDexMetadata() throws IOException {
+ // Setup
+ Path dexMetadataPath = null;
+ Path apk = null;
+ try {
+ dexMetadataPath = createDexMetadata(PROFILE_DEX_METADATA, VDEX_DEX_METADATA);
+ apk = zipFiles(".apk", DEX, NON_DEX, dexMetadataPath);
+
+ // Act
+ ArtStatsLogUtils.writeStatsLog(
+ mockLogger,
+ SESSION_ID,
+ apk.toString(),
+ COMPILER_FILTER,
+ UID,
+ COMPILE_TIME,
+ dexMetadataPath.toString(),
+ COMPILATION_REASON,
+ RESULT_CODE);
+
+ // Assert
+ verifyWrites(ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__PROFILE_AND_VDEX);
+ } finally {
+ deleteSliently(dexMetadataPath);
+ deleteSliently(apk);
+ }
+ }
+
+ @Test
+ public void testProfileOnlyDexMetadata() throws IOException {
+ // Setup
+ Path dexMetadataPath = null;
+ Path apk = null;
+ try {
+ dexMetadataPath = createDexMetadata(PROFILE_DEX_METADATA);
+ apk = zipFiles(".apk", DEX, NON_DEX, dexMetadataPath);
+
+ // Act
+ ArtStatsLogUtils.writeStatsLog(
+ mockLogger,
+ SESSION_ID,
+ apk.toString(),
+ COMPILER_FILTER,
+ UID,
+ COMPILE_TIME,
+ dexMetadataPath.toString(),
+ COMPILATION_REASON,
+ RESULT_CODE);
+
+ // Assert
+ verifyWrites(ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__PROFILE);
+ } finally {
+ deleteSliently(dexMetadataPath);
+ deleteSliently(apk);
+ }
+ }
+
+ @Test
+ public void testVdexOnlyDexMetadata() throws IOException {
+ // Setup
+ Path dexMetadataPath = null;
+ Path apk = null;
+ try {
+ dexMetadataPath = createDexMetadata(VDEX_DEX_METADATA);
+ apk = zipFiles(".apk", DEX, NON_DEX, dexMetadataPath);
+
+ // Act
+ ArtStatsLogUtils.writeStatsLog(
+ mockLogger,
+ SESSION_ID,
+ apk.toString(),
+ COMPILER_FILTER,
+ UID,
+ COMPILE_TIME,
+ dexMetadataPath.toString(),
+ COMPILATION_REASON,
+ RESULT_CODE);
+
+ // Assert
+ verifyWrites(ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__VDEX);
+ } finally {
+ deleteSliently(dexMetadataPath);
+ deleteSliently(apk);
+ }
+ }
+
+ @Test
+ public void testNoneDexMetadata() throws IOException {
+ // Setup
+ Path apk = null;
+ try {
+ apk = zipFiles(".apk", DEX, NON_DEX);
+
+ // Act
+ ArtStatsLogUtils.writeStatsLog(
+ mockLogger,
+ SESSION_ID,
+ apk.toString(),
+ COMPILER_FILTER,
+ UID,
+ COMPILE_TIME,
+ /*dexMetadataPath=*/ null,
+ COMPILATION_REASON,
+ RESULT_CODE);
+
+ // Assert
+ verifyWrites(ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__NONE_DEX_METADATA);
+ } finally {
+ deleteSliently(apk);
+ }
+ }
+
+ @Test
+ public void testUnKnownDexMetadata() throws IOException {
+ // Setup
+ Path dexMetadataPath = null;
+ Path apk = null;
+ try {
+ dexMetadataPath = createDexMetadata("unknown");
+ apk = zipFiles(".apk", DEX, NON_DEX, dexMetadataPath);
+
+ // Act
+ ArtStatsLogUtils.writeStatsLog(
+ mockLogger,
+ SESSION_ID,
+ apk.toString(),
+ COMPILER_FILTER,
+ UID,
+ COMPILE_TIME,
+ dexMetadataPath.toString(),
+ COMPILATION_REASON,
+ RESULT_CODE);
+
+ // Assert
+ verifyWrites(ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__UNKNOWN_DEX_METADATA);
+ } finally {
+ deleteSliently(dexMetadataPath);
+ deleteSliently(apk);
+ }
+ }
+
+ private void verifyWrites(int dexMetadataType) {
+ InOrder inorder = inOrder(mockLogger);
+ inorder.verify(mockLogger).write(
+ SESSION_ID, UID,
+ COMPILATION_REASON,
+ COMPILER_FILTER,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE,
+ RESULT_CODE,
+ dexMetadataType);
+ inorder.verify(mockLogger).write(
+ SESSION_ID,
+ UID,
+ COMPILATION_REASON,
+ COMPILER_FILTER,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES,
+ DEX_CONTENT.length,
+ dexMetadataType);
+ inorder.verify(mockLogger).write(
+ SESSION_ID,
+ UID,
+ COMPILATION_REASON,
+ COMPILER_FILTER,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
+ COMPILE_TIME,
+ dexMetadataType);
+ }
+
+ private Path zipFiles(String suffix, Path... files) throws IOException {
+ Path zipFile = Files.createTempFile(null, suffix);
+ try (final OutputStream os = Files.newOutputStream(zipFile)) {
+ try (final ZipOutputStream zos = new ZipOutputStream(os)) {
+ for (Path file : files) {
+ ZipEntry zipEntry = new ZipEntry(file.getFileName().toString());
+ zos.putNextEntry(zipEntry);
+ zos.write(Files.readAllBytes(file));
+ zos.closeEntry();
+ }
+ }
+ }
+ return zipFile;
+ }
+
+ private Path createDexMetadata(String... entryNames) throws IOException {
+ Path zipFile = Files.createTempFile(null, ".dm");
+ try (final OutputStream os = Files.newOutputStream(zipFile)) {
+ try (final ZipOutputStream zos = new ZipOutputStream(os)) {
+ for (String entryName : entryNames) {
+ ZipEntry zipEntry = new ZipEntry(entryName);
+ zos.putNextEntry(zipEntry);
+ zos.write(entryName.getBytes());
+ zos.closeEntry();
+ }
+ }
+ }
+ return zipFile;
+ }
+
+ private static void deleteSliently(Path file) {
+ if (file != null) {
+ try {
+ Files.deleteIfExists(file);
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+}
diff --git a/telecomm/java/android/telecom/CallDiagnosticService.java b/telecomm/java/android/telecom/CallDiagnosticService.java
index 809f2bc..5fb6b33 100644
--- a/telecomm/java/android/telecom/CallDiagnosticService.java
+++ b/telecomm/java/android/telecom/CallDiagnosticService.java
@@ -27,6 +27,8 @@
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.RemoteException;
+import android.telephony.Annotation;
+import android.telephony.ims.ImsReasonInfo;
import android.util.ArrayMap;
import com.android.internal.telecom.ICallDiagnosticService;
@@ -105,6 +107,12 @@
throws RemoteException {
handleBluetoothCallQualityReport(qualityReport);
}
+
+ @Override
+ public void notifyCallDisconnected(@NonNull String callId,
+ @NonNull DisconnectCause disconnectCause) throws RemoteException {
+ handleCallDisconnected(callId, disconnectCause);
+ }
}
/**
@@ -329,6 +337,32 @@
}
/**
+ * Handles a request from the Telecom framework to get a disconnect message from the
+ * {@link CallDiagnosticService}.
+ * @param callId The ID of the call.
+ * @param disconnectCause The telecom disconnect cause.
+ */
+ private void handleCallDisconnected(@NonNull String callId,
+ @NonNull DisconnectCause disconnectCause) {
+ Log.i(this, "handleCallDisconnected: call=%s; cause=%s", callId, disconnectCause);
+ DiagnosticCall diagnosticCall = mDiagnosticCallByTelecomCallId.get(callId);
+ CharSequence message;
+ if (disconnectCause.getImsReasonInfo() != null) {
+ message = diagnosticCall.onCallDisconnected(disconnectCause.getImsReasonInfo());
+ } else {
+ message = diagnosticCall.onCallDisconnected(
+ disconnectCause.getTelephonyDisconnectCause(),
+ disconnectCause.getTelephonyPreciseDisconnectCause());
+ }
+ try {
+ mAdapter.overrideDisconnectMessage(callId, message);
+ } catch (RemoteException e) {
+ Log.w(this, "handleCallDisconnected: call=%s; cause=%s; %s",
+ callId, disconnectCause, e);
+ }
+ }
+
+ /**
* Handles an incoming bluetooth call quality report from Telecom. Notifies via
* {@link CallDiagnosticService#onBluetoothCallQualityReportReceived(
* BluetoothCallQualityReport)}.
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index 1472a4a..ed7b79f 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -16,9 +16,13 @@
package android.telecom;
+import android.annotation.Nullable;
import android.media.ToneGenerator;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.Annotation;
+import android.telephony.PreciseDisconnectCause;
+import android.telephony.ims.ImsReasonInfo;
import android.text.TextUtils;
import java.util.Objects;
@@ -112,6 +116,9 @@
private CharSequence mDisconnectDescription;
private String mDisconnectReason;
private int mToneToPlay;
+ private int mTelephonyDisconnectCause;
+ private int mTelephonyPreciseDisconnectCause;
+ private ImsReasonInfo mImsReasonInfo;
/**
* Creates a new DisconnectCause.
@@ -155,11 +162,36 @@
*/
public DisconnectCause(int code, CharSequence label, CharSequence description, String reason,
int toneToPlay) {
+ this(code, label, description, reason, toneToPlay,
+ android.telephony.DisconnectCause.ERROR_UNSPECIFIED,
+ PreciseDisconnectCause.ERROR_UNSPECIFIED,
+ null /* imsReasonInfo */);
+ }
+
+ /**
+ * Creates a new DisconnectCause instance.
+ * @param code The code for the disconnect cause.
+ * @param label The localized label to show to the user to explain the disconnect.
+ * @param description The localized description to show to the user to explain the disconnect.
+ * @param reason The reason for the disconnect.
+ * @param toneToPlay The tone to play on disconnect, as defined in {@link ToneGenerator}.
+ * @param telephonyDisconnectCause The Telephony disconnect cause.
+ * @param telephonyPreciseDisconnectCause The Telephony precise disconnect cause.
+ * @param imsReasonInfo The relevant {@link ImsReasonInfo}, or {@code null} if not available.
+ * @hide
+ */
+ public DisconnectCause(int code, CharSequence label, CharSequence description, String reason,
+ int toneToPlay, @Annotation.DisconnectCauses int telephonyDisconnectCause,
+ @Annotation.PreciseDisconnectCauses int telephonyPreciseDisconnectCause,
+ @Nullable ImsReasonInfo imsReasonInfo) {
mDisconnectCode = code;
mDisconnectLabel = label;
mDisconnectDescription = description;
mDisconnectReason = reason;
mToneToPlay = toneToPlay;
+ mTelephonyDisconnectCause = telephonyDisconnectCause;
+ mTelephonyPreciseDisconnectCause = telephonyPreciseDisconnectCause;
+ mImsReasonInfo = imsReasonInfo;
}
/**
@@ -209,6 +241,33 @@
}
/**
+ * Returns the telephony {@link android.telephony.DisconnectCause} for the call.
+ * @return The disconnect cause.
+ * @hide
+ */
+ public @Annotation.DisconnectCauses int getTelephonyDisconnectCause() {
+ return mTelephonyDisconnectCause;
+ }
+
+ /**
+ * Returns the telephony {@link android.telephony.PreciseDisconnectCause} for the call.
+ * @return The precise disconnect cause.
+ * @hide
+ */
+ public @Annotation.PreciseDisconnectCauses int getTelephonyPreciseDisconnectCause() {
+ return mTelephonyPreciseDisconnectCause;
+ }
+
+ /**
+ * Returns the telephony {@link ImsReasonInfo} associated with the call disconnection.
+ * @return The {@link ImsReasonInfo} or {@code null} if not known.
+ * @hide
+ */
+ public @Nullable ImsReasonInfo getImsReasonInfo() {
+ return mImsReasonInfo;
+ }
+
+ /**
* Returns the tone to play when disconnected.
*
* @return the tone as defined in {@link ToneGenerator} to play when disconnected.
@@ -217,7 +276,8 @@
return mToneToPlay;
}
- public static final @android.annotation.NonNull Creator<DisconnectCause> CREATOR = new Creator<DisconnectCause>() {
+ public static final @android.annotation.NonNull Creator<DisconnectCause> CREATOR
+ = new Creator<DisconnectCause>() {
@Override
public DisconnectCause createFromParcel(Parcel source) {
int code = source.readInt();
@@ -225,7 +285,11 @@
CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
String reason = source.readString();
int tone = source.readInt();
- return new DisconnectCause(code, label, description, reason, tone);
+ int telephonyDisconnectCause = source.readInt();
+ int telephonyPreciseDisconnectCause = source.readInt();
+ ImsReasonInfo imsReasonInfo = source.readParcelable(null);
+ return new DisconnectCause(code, label, description, reason, tone,
+ telephonyDisconnectCause, telephonyPreciseDisconnectCause, imsReasonInfo);
}
@Override
@@ -241,6 +305,9 @@
TextUtils.writeToParcel(mDisconnectDescription, destination, flags);
destination.writeString(mDisconnectReason);
destination.writeInt(mToneToPlay);
+ destination.writeInt(mTelephonyDisconnectCause);
+ destination.writeInt(mTelephonyPreciseDisconnectCause);
+ destination.writeParcelable(mImsReasonInfo, 0);
}
@Override
@@ -254,7 +321,10 @@
+ Objects.hashCode(mDisconnectLabel)
+ Objects.hashCode(mDisconnectDescription)
+ Objects.hashCode(mDisconnectReason)
- + Objects.hashCode(mToneToPlay);
+ + Objects.hashCode(mToneToPlay)
+ + Objects.hashCode(mTelephonyDisconnectCause)
+ + Objects.hashCode(mTelephonyPreciseDisconnectCause)
+ + Objects.hashCode(mImsReasonInfo);
}
@Override
@@ -265,7 +335,11 @@
&& Objects.equals(mDisconnectLabel, d.getLabel())
&& Objects.equals(mDisconnectDescription, d.getDescription())
&& Objects.equals(mDisconnectReason, d.getReason())
- && Objects.equals(mToneToPlay, d.getTone());
+ && Objects.equals(mToneToPlay, d.getTone())
+ && Objects.equals(mTelephonyDisconnectCause, d.getTelephonyDisconnectCause())
+ && Objects.equals(mTelephonyPreciseDisconnectCause,
+ d.getTelephonyPreciseDisconnectCause())
+ && Objects.equals(mImsReasonInfo, d.getImsReasonInfo());
}
return false;
}
@@ -325,6 +399,11 @@
+ " Label: (" + label + ")"
+ " Description: (" + description + ")"
+ " Reason: (" + reason + ")"
- + " Tone: (" + mToneToPlay + ") ]";
+ + " Tone: (" + mToneToPlay + ") "
+ + " TelephonyCause: " + mTelephonyDisconnectCause + "/"
+ + mTelephonyPreciseDisconnectCause
+ + " ImsReasonInfo: "
+ + mImsReasonInfo
+ + "]";
}
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl b/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl
index 65b4d19..fc9879a 100644
--- a/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl
@@ -18,6 +18,7 @@
import android.telecom.BluetoothCallQualityReport;
import android.telecom.CallAudioState;
+import android.telecom.DisconnectCause;
import android.telecom.ParcelableCall;
import com.android.internal.telecom.ICallDiagnosticServiceAdapter;
@@ -34,4 +35,5 @@
void removeDiagnosticCall(in String callId);
void receiveDeviceToDeviceMessage(in String callId, int message, int value);
void receiveBluetoothCallQualityReport(in BluetoothCallQualityReport qualityReport);
+ void notifyCallDisconnected(in String callId, in DisconnectCause disconnectCause);
}
diff --git a/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp b/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp
index ce226fd..926ff4d 100644
--- a/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp
+++ b/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp
@@ -130,6 +130,9 @@
return result;
}
sBuffers[slot] = anb;
+ if (timeoutMs == 0) {
+ return android::OK;
+ }
android::sp<android::Fence> fence(new android::Fence(fenceFd));
int waitResult = fence->wait(timeoutMs);
if (waitResult != android::OK) {
@@ -197,6 +200,28 @@
return result;
}
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetAsyncMode(JNIEnv* /* env */,
+ jclass /* clazz */,
+ jboolean async) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ return surface->setAsyncMode(async);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetDequeueTimeout(
+ JNIEnv* /* env */, jclass /* clazz */, jlong timeoutMs) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ return surface->setDequeueTimeout(timeoutMs);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetMaxDequeuedBufferCount(
+ JNIEnv* /* env */, jclass /* clazz */, jint maxDequeuedBuffers) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ return surface->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+}
+
JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetBufferCount(
JNIEnv* /* env */, jclass /* clazz */, jint count) {
assert(sAnw);
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
index 7d278dc..b67dc380 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
@@ -17,6 +17,7 @@
import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -93,4 +94,80 @@
assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
}
+
+ @Test
+ // Leave IGBP in sync mode, try to dequeue and queue as fast as possible. Check that we
+ // occasionally get timeout errors.
+ fun testSyncMode_dequeueWithoutBlockingFails() {
+ val numFrames = 1000L
+ runOnUiThread { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L))
+ var failures = false
+ for (i in 1..numFrames) {
+ if (activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */) != 0) {
+ failures = true
+ break
+ }
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ assertTrue(failures)
+ }
+ }
+
+ @Test
+ // Set IGBP to be in async mode, try to dequeue and queue as fast as possible. Client should be
+ // able to dequeue and queue buffers without being blocked.
+ fun testAsyncMode_dequeueWithoutBlocking() {
+ val numFrames = 1000L
+ runOnUiThread { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetAsyncMode(async = true))
+ for (i in 1..numFrames) {
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */))
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ }
+ }
+
+ @Test
+ // Disable triple buffering in the system and leave IGBP in sync mode. Check that we
+ // occasionally get timeout errors.
+ fun testSyncModeWithDisabledTripleBuffering_dequeueWithoutBlockingFails() {
+ val numFrames = 1000L
+ runOnUiThread { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetMaxDequeuedBufferCount(1))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L))
+ var failures = false
+ for (i in 1..numFrames) {
+ if (activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */) != 0) {
+ failures = true
+ break
+ }
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ assertTrue(failures)
+ }
+ }
+
+ @Test
+ // Disable triple buffering in the system and set IGBP to be in async mode. Try to dequeue and
+ // queue as fast as possible. Without triple buffering, the client does not have an extra buffer
+ // to dequeue and will not be able to dequeue and queue buffers without being blocked.
+ fun testAsyncModeWithDisabledTripleBuffering_dequeueWithoutBlockingFails() {
+ val numFrames = 1000L
+ runOnUiThread { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetMaxDequeuedBufferCount(1))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetAsyncMode(async = true))
+ var failures = false
+ for (i in 1..numFrames) {
+ if (activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */) != 0) {
+ failures = true
+ break
+ }
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ assertTrue(failures)
+ }
+ }
}
\ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt
index cfbd3ac..45a7094 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt
@@ -54,7 +54,13 @@
external fun SurfaceSetScalingMode(scalingMode: Int)
external fun SurfaceDequeueBuffer(slot: Int, timeoutMs: Int): Int
external fun SurfaceCancelBuffer(slot: Int)
- external fun SurfaceQueueBuffer(slot: Int, freeSlot: Boolean = true)
+ external fun SurfaceQueueBuffer(slot: Int, freeSlot: Boolean = true): Int
+ external fun SurfaceSetAsyncMode(async: Boolean): Int
+ external fun SurfaceSetDequeueTimeout(timeout: Long): Int
+ external fun SurfaceQuery(what: Int): Int
+ external fun SurfaceSetMaxDequeuedBufferCount(maxDequeuedBuffers: Int): Int
+
+ // system/native_window.h functions
external fun NativeWindowSetBufferCount(count: Int): Int
external fun NativeWindowSetSharedBufferMode(shared: Boolean): Int
external fun NativeWindowSetAutoRefresh(autoRefresh: Boolean): Int
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index a07bce3..8932892 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -30,12 +30,21 @@
* -e selectTest_verbose true \
* com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
* </pre>
+ *
+ * <p>Use this filter when running FrameworksMockingCoreTests as
+ * <pre>
+ * adb shell am instrument -w \
+ * -e filter com.android.server.wm.test.filters.FrameworksTestsFilter \
+ * -e selectTest_verbose true \
+ * com.android.frameworks.mockingcoretests/androidx.test.runner.AndroidJUnitRunner
+ * </pre>
*/
public final class FrameworksTestsFilter extends SelectTest {
private static final String[] SELECTED_TESTS = {
// Test specifications for FrameworksMockingCoreTests.
"android.app.activity.ActivityThreadClientTest",
+ "android.view.DisplayTest",
// Test specifications for FrameworksCoreTests.
"android.app.servertransaction.", // all tests under the package.
"android.view.CutoutSpecificationTest",