Merge "AudioService BtHelper: fix isBluetoothScoOn()" into rvc-dev
diff --git a/apex/Android.bp b/apex/Android.bp
index 51e030b..e8afa1d 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -63,6 +63,60 @@
"--hide-annotation android.annotation.Hide " +
"--hide InternalClasses " // com.android.* classes are okay in this interface
+// Defaults for mainline module provided java_sdk_library instances.
+java_defaults {
+ name: "framework-module-defaults",
+
+ // Additional annotations used for compiling both the implementation and the
+ // stubs libraries.
+ libs: ["framework-annotations-lib"],
+
+ // Enable api lint. This will eventually become the default for java_sdk_library
+ // but it cannot yet be turned on because some usages have not been cleaned up.
+ // TODO(b/156126315) - Remove when no longer needed.
+ api_lint: {
+ enabled: true,
+ },
+
+ // The API scope specific properties.
+ public: {
+ enabled: true,
+ sdk_version: "module_current",
+ },
+ system: {
+ enabled: true,
+ sdk_version: "module_current",
+ },
+ module_lib: {
+ enabled: true,
+ sdk_version: "module_current",
+ },
+
+ // The stub libraries must be visible to frameworks/base so they can be combined
+ // into API specific libraries.
+ stubs_library_visibility: [
+ "//frameworks/base", // Framework
+ ],
+
+ // Set the visibility of the modules creating the stubs source.
+ stubs_source_visibility: [
+ // Ignore any visibility rules specified on the java_sdk_library when
+ // setting the visibility of the stubs source modules.
+ "//visibility:override",
+
+ // Currently, the stub source is not required for anything other than building
+ // the stubs library so is private to avoid misuse.
+ "//visibility:private",
+ ],
+
+ // Collates API usages from each module for further analysis.
+ plugins: ["java_api_finder"],
+
+ // Mainline modules should only rely on 'module_lib' APIs provided by other modules
+ // and the non updatable parts of the platform.
+ sdk_version: "module_current",
+}
+
stubs_defaults {
name: "framework-module-stubs-defaults-publicapi",
args: mainline_framework_stubs_args,
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index 46d449a..372ec98 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -79,6 +79,12 @@
private static final int STANDBY_BUCKET_UNKNOWN = -1;
+ /**
+ * The bucket beyond which apps are considered idle. Any apps in this bucket or lower are
+ * considered idle while those in higher buckets are not considered idle.
+ */
+ static final int IDLE_BUCKET_CUTOFF = STANDBY_BUCKET_RARE;
+
@VisibleForTesting
static final String APP_IDLE_FILENAME = "app_idle_stats.xml";
private static final String TAG_PACKAGES = "packages";
@@ -350,7 +356,7 @@
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
AppUsageHistory appUsageHistory =
getPackageHistory(userHistory, packageName, elapsedRealtime, true);
- return appUsageHistory.currentBucket >= STANDBY_BUCKET_RARE;
+ return appUsageHistory.currentBucket >= IDLE_BUCKET_CUTOFF;
}
public AppUsageHistory getAppUsageHistory(String packageName, int userId,
@@ -487,7 +493,7 @@
final int newBucket;
final int reason;
if (idle) {
- newBucket = STANDBY_BUCKET_RARE;
+ newBucket = IDLE_BUCKET_CUTOFF;
reason = REASON_MAIN_FORCED_BY_USER;
} else {
newBucket = STANDBY_BUCKET_ACTIVE;
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 980372d..2834ab1 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -54,6 +54,7 @@
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppGlobals;
@@ -92,6 +93,7 @@
import android.os.UserHandle;
import android.provider.Settings.Global;
import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.KeyValueListParser;
import android.util.Slog;
@@ -227,6 +229,13 @@
@GuardedBy("mActiveAdminApps")
private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>();
+ /**
+ * Set of system apps that are headless (don't have any declared activities, enabled or
+ * disabled). Presence in this map indicates that the app is a headless system app.
+ */
+ @GuardedBy("mAppIdleLock")
+ private final ArrayMap<String, Boolean> mHeadlessSystemApps = new ArrayMap<>();
+
private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1);
// Messages for the handler
@@ -667,20 +676,22 @@
return;
}
}
- final boolean isSpecial = isAppSpecial(packageName,
+ final int minBucket = getAppMinBucket(packageName,
UserHandle.getAppId(uid),
userId);
if (DEBUG) {
- Slog.d(TAG, " Checking idle state for " + packageName + " special=" +
- isSpecial);
+ Slog.d(TAG, " Checking idle state for " + packageName
+ + " minBucket=" + minBucket);
}
- if (isSpecial) {
+ if (minBucket <= STANDBY_BUCKET_ACTIVE) {
+ // No extra processing needed for ACTIVE or higher since apps can't drop into lower
+ // buckets.
synchronized (mAppIdleLock) {
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
- STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT);
+ minBucket, REASON_MAIN_DEFAULT);
}
maybeInformListeners(packageName, userId, elapsedRealtime,
- STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT, false);
+ minBucket, REASON_MAIN_DEFAULT, false);
} else {
synchronized (mAppIdleLock) {
final AppIdleHistory.AppUsageHistory app =
@@ -761,6 +772,14 @@
Slog.d(TAG, "Bringing up from RESTRICTED to RARE due to off switch");
}
}
+ if (newBucket > minBucket) {
+ newBucket = minBucket;
+ // Leave the reason alone.
+ if (DEBUG) {
+ Slog.d(TAG, "Bringing up from " + newBucket + " to " + minBucket
+ + " due to min bucketing");
+ }
+ }
if (DEBUG) {
Slog.d(TAG, " Old bucket=" + oldBucket
+ ", newBucket=" + newBucket);
@@ -1027,20 +1046,35 @@
return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
}
- private boolean isAppSpecial(String packageName, int appId, int userId) {
- if (packageName == null) return false;
+ @StandbyBuckets
+ private int getAppMinBucket(String packageName, int userId) {
+ try {
+ final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+ return getAppMinBucket(packageName, UserHandle.getAppId(uid), userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Not a valid package for this user, nothing to do
+ return STANDBY_BUCKET_NEVER;
+ }
+ }
+
+ /**
+ * Return the lowest bucket this app should ever enter.
+ */
+ @StandbyBuckets
+ private int getAppMinBucket(String packageName, int appId, int userId) {
+ if (packageName == null) return STANDBY_BUCKET_NEVER;
// If not enabled at all, of course nobody is ever idle.
if (!mAppIdleEnabled) {
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
if (appId < Process.FIRST_APPLICATION_UID) {
// System uids never go idle.
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
if (packageName.equals("android")) {
// Nor does the framework (which should be redundant with the above, but for MR1 we will
// retain this for safety).
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
if (mSystemServicesReady) {
try {
@@ -1048,42 +1082,51 @@
// for idle mode, because app idle (aka app standby) is really not as big an issue
// for controlling who participates vs. doze mode.
if (mInjector.isNonIdleWhitelisted(packageName)) {
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
if (isActiveDeviceAdmin(packageName, userId)) {
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
if (isActiveNetworkScorer(packageName)) {
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
if (mAppWidgetManager != null
&& mInjector.isBoundWidgetPackage(mAppWidgetManager, packageName, userId)) {
- return true;
+ // TODO: consider lowering to ACTIVE
+ return STANDBY_BUCKET_EXEMPTED;
}
if (isDeviceProvisioningPackage(packageName)) {
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
}
// Check this last, as it can be the most expensive check
if (isCarrierApp(packageName)) {
- return true;
+ return STANDBY_BUCKET_EXEMPTED;
}
- return false;
+ if (isHeadlessSystemApp(packageName)) {
+ return STANDBY_BUCKET_ACTIVE;
+ }
+
+ return STANDBY_BUCKET_NEVER;
+ }
+
+ private boolean isHeadlessSystemApp(String packageName) {
+ return mHeadlessSystemApps.containsKey(packageName);
}
@Override
public boolean isAppIdleFiltered(String packageName, int appId, int userId,
long elapsedRealtime) {
- if (isAppSpecial(packageName, appId, userId)) {
+ if (getAppMinBucket(packageName, appId, userId) < AppIdleHistory.IDLE_BUCKET_CUTOFF) {
return false;
} else {
synchronized (mAppIdleLock) {
@@ -1423,6 +1466,8 @@
}
}
+ // Make sure we don't put the app in a lower bucket than it's supposed to be in.
+ newBucket = Math.min(newBucket, getAppMinBucket(packageName, userId));
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
reason, resetTimeout);
}
@@ -1617,14 +1662,16 @@
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
+ final String pkgName = intent.getData().getSchemeSpecificPart();
+ final int userId = getSendingUserId();
if (Intent.ACTION_PACKAGE_ADDED.equals(action)
|| Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
clearCarrierPrivilegedApps();
+ // ACTION_PACKAGE_ADDED is called even for system app downgrades.
+ evaluateSystemAppException(pkgName, userId);
}
if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
Intent.ACTION_PACKAGE_ADDED.equals(action))) {
- final String pkgName = intent.getData().getSchemeSpecificPart();
- final int userId = getSendingUserId();
if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
maybeUnrestrictBuggyApp(pkgName, userId);
} else {
@@ -1634,6 +1681,34 @@
}
}
+ private void evaluateSystemAppException(String packageName, int userId) {
+ if (!mSystemServicesReady) {
+ // The app will be evaluated in initializeDefaultsForSystemApps() when possible.
+ return;
+ }
+ try {
+ PackageInfo pi = mPackageManager.getPackageInfoAsUser(packageName,
+ PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DISABLED_COMPONENTS,
+ userId);
+ evaluateSystemAppException(pi);
+ } catch (PackageManager.NameNotFoundException e) {
+ mHeadlessSystemApps.remove(packageName);
+ }
+ }
+
+ private void evaluateSystemAppException(@Nullable PackageInfo pkgInfo) {
+ if (pkgInfo.applicationInfo != null && pkgInfo.applicationInfo.isSystemApp()) {
+ synchronized (mAppIdleLock) {
+ if (pkgInfo.activities == null || pkgInfo.activities.length == 0) {
+ // Headless system app.
+ mHeadlessSystemApps.put(pkgInfo.packageName, true);
+ } else {
+ mHeadlessSystemApps.remove(pkgInfo.packageName);
+ }
+ }
+ }
+ }
+
@Override
public void initializeDefaultsForSystemApps(int userId) {
if (!mSystemServicesReady) {
@@ -1645,7 +1720,7 @@
+ "appIdleEnabled=" + mAppIdleEnabled);
final long elapsedRealtime = mInjector.elapsedRealtime();
List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
- PackageManager.MATCH_DISABLED_COMPONENTS,
+ PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DISABLED_COMPONENTS,
userId);
final int packageCount = packages.size();
synchronized (mAppIdleLock) {
@@ -1658,6 +1733,8 @@
mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE,
REASON_SUB_USAGE_SYSTEM_UPDATE, 0,
elapsedRealtime + mSystemUpdateUsageTimeoutMillis);
+
+ evaluateSystemAppException(pi);
}
}
// Immediately persist defaults to disk
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index c3adf60..ddecfed 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.annotation.StringDef;
import android.media.MediaCodec.CryptoInfo;
+import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -1099,6 +1100,9 @@
// Private methods.
private MediaParser(OutputConsumer outputConsumer, boolean sniff, String... parserNamesPool) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ throw new UnsupportedOperationException("Android version must be R or greater.");
+ }
mParserParameters = new HashMap<>();
mOutputConsumer = outputConsumer;
mParserNamesPool = parserNamesPool;
diff --git a/apex/sdkextensions/Android.bp b/apex/sdkextensions/Android.bp
index dbb5bd3d..fdb078e 100644
--- a/apex/sdkextensions/Android.bp
+++ b/apex/sdkextensions/Android.bp
@@ -39,7 +39,7 @@
sdk {
name: "sdkextensions-sdk",
- java_header_libs: [ "framework-sdkextensions-stubs-systemapi" ],
+ java_sdk_libs: [ "framework-sdkextensions" ],
}
apex_key {
diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index 14e23ed..b8aad7d 100644
--- a/apex/sdkextensions/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -25,14 +25,18 @@
visibility: [ "//frameworks/base" ] // For the "global" stubs.
}
-java_library {
+java_sdk_library {
name: "framework-sdkextensions",
srcs: [ ":framework-sdkextensions-sources" ],
- sdk_version: "system_current",
- libs: [ "framework-annotations-lib" ],
+ defaults: ["framework-module-defaults"],
+
+ // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
+ // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
+ // modules to java_sdk_library.
+ naming_scheme: "framework-modules",
+
permitted_packages: [ "android.os.ext" ],
installable: true,
- plugins: ["java_api_finder"],
visibility: [
"//frameworks/base/apex/sdkextensions",
"//frameworks/base/apex/sdkextensions/testing",
@@ -43,102 +47,3 @@
"test_com.android.sdkext",
],
}
-
-stubs_defaults {
- name: "framework-sdkextensions-stubs-defaults",
- srcs: [ ":framework-sdkextensions-sources" ],
- libs: [ "framework-annotations-lib" ],
- dist: { dest: "framework-sdkextensions.txt" },
-}
-
-droidstubs {
- name: "framework-sdkextensions-stubs-srcs-publicapi",
- defaults: [
- "framework-module-stubs-defaults-publicapi",
- "framework-sdkextensions-stubs-defaults",
- ],
- check_api: {
- last_released: {
- api_file: ":framework-sdkextensions.api.public.latest",
- removed_api_file: ":framework-sdkextensions-removed.api.public.latest",
- },
- api_lint: {
- new_since: ":framework-sdkextensions.api.public.latest",
- },
- },
-}
-
-droidstubs {
- name: "framework-sdkextensions-stubs-srcs-systemapi",
- defaults: [
- "framework-module-stubs-defaults-systemapi",
- "framework-sdkextensions-stubs-defaults",
- ],
- check_api: {
- last_released: {
- api_file: ":framework-sdkextensions.api.system.latest",
- removed_api_file: ":framework-sdkextensions-removed.api.system.latest",
- },
- api_lint: {
- new_since: ":framework-sdkextensions.api.system.latest",
- },
- },
-}
-
-droidstubs {
- name: "framework-sdkextensions-api-module_libs_api",
- defaults: [
- "framework-module-api-defaults-module_libs_api",
- "framework-sdkextensions-stubs-defaults",
- ],
- check_api: {
- last_released: {
- api_file: ":framework-sdkextensions.api.module-lib.latest",
- removed_api_file: ":framework-sdkextensions-removed.api.module-lib.latest",
- },
- api_lint: {
- new_since: ":framework-sdkextensions.api.module-lib.latest",
- },
- },
-}
-
-droidstubs {
- name: "framework-sdkextensions-stubs-srcs-module_libs_api",
- defaults: [
- "framework-module-stubs-defaults-module_libs_api",
- "framework-sdkextensions-stubs-defaults",
- ],
-}
-
-java_library {
- name: "framework-sdkextensions-stubs-publicapi",
- srcs: [":framework-sdkextensions-stubs-srcs-publicapi"],
- defaults: ["framework-module-stubs-lib-defaults-publicapi"],
- visibility: [
- "//frameworks/base", // Framework
- "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
- ],
- dist: { dest: "framework-sdkextensions.jar" },
-}
-
-java_library {
- name: "framework-sdkextensions-stubs-systemapi",
- srcs: [":framework-sdkextensions-stubs-srcs-systemapi"],
- defaults: ["framework-module-stubs-lib-defaults-systemapi"],
- visibility: [
- "//frameworks/base", // Framework
- "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
- ],
- dist: { dest: "framework-sdkextensions.jar" },
-}
-
-java_library {
- name: "framework-sdkextensions-stubs-module_libs_api",
- srcs: [":framework-sdkextensions-stubs-srcs-module_libs_api"],
- defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
- visibility: [
- "//frameworks/base", // Framework
- "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
- ],
- dist: { dest: "framework-sdkextensions.jar" },
-}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 926d8fc..0410c90 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -336,7 +336,7 @@
* an input channel where the client can receive input.
*/
void grantInputChannel(int displayId, in SurfaceControl surface, in IWindow window,
- in IBinder hostInputToken, int flags, out InputChannel outInputChannel);
+ in IBinder hostInputToken, int flags, int type, out InputChannel outInputChannel);
/**
* Update the flags on an input channel associated with a particular surface.
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index dbbe4b6..a480072 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -208,26 +208,6 @@
}
/**
- * Called by {@link ViewRootImpl} to feedback the state of the screen for this view.
- * @param newScreenState The new state of the screen. Can be either
- * {@link View#SCREEN_STATE_ON} or {@link View#SCREEN_STATE_OFF}
- */
- @UiThread
- void onScreenStateChanged(int newScreenState) {
- if (!getImmDelegate().isCurrentRootView(mViewRootImpl)) {
- return;
- }
- // Close input connection and IME when the screen is turn off for security concern.
- if (newScreenState == View.SCREEN_STATE_OFF && mServedView != null) {
- if (DEBUG) {
- Log.d(TAG, "onScreenStateChanged, disconnect input when screen turned off");
- }
- mNextServedView = null;
- mViewRootImpl.dispatchCheckFocus();
- }
- }
-
- /**
* @param windowAttribute {@link WindowManager.LayoutParams} to be checked.
* @return Whether the window is in local focus mode or not.
*/
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 7086dc0..3850781 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -275,12 +275,4 @@
// ViewRoot will release mSurfaceControl for us.
mViewRoot.die(false /* immediate */);
}
-
- /**
- * Tell this viewroot to clean itself up.
- * @hide
- */
- public void die() {
- mViewRoot.die(false /* immediate */);
- }
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5b9cd77..d36a238 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1496,7 +1496,6 @@
final int newScreenState = toViewScreenState(newDisplayState);
if (oldScreenState != newScreenState) {
mView.dispatchScreenStateChanged(newScreenState);
- mImeFocusController.onScreenStateChanged(newScreenState);
}
if (oldDisplayState == Display.STATE_OFF) {
// Draw was suppressed so we need to for it to happen here.
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index cd954c4..d20ffb3 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -143,7 +143,7 @@
WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) {
try {
mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags,
- outInputChannel);
+ attrs.type, outInputChannel);
} catch (RemoteException e) {
Log.e(TAG, "Failed to grant input to surface: ", e);
}
@@ -432,7 +432,7 @@
@Override
public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window,
- IBinder hostInputToken, int flags, InputChannel outInputChannel) {
+ IBinder hostInputToken, int flags, int type, InputChannel outInputChannel) {
}
@Override
diff --git a/core/res/res/layout/resolver_empty_states.xml b/core/res/res/layout/resolver_empty_states.xml
index fe11769..196a0e8 100644
--- a/core/res/res/layout/resolver_empty_states.xml
+++ b/core/res/res/layout/resolver_empty_states.xml
@@ -59,7 +59,7 @@
<Button
android:id="@+id/resolver_empty_state_button"
android:layout_below="@+id/resolver_empty_state_subtitle"
- android:layout_marginTop="16dp"
+ android:layout_marginTop="8dp"
android:text="@string/resolver_switch_on_work"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 1d06df0..008a433 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -475,5 +475,10 @@
public void onRequestFailed(int reason) {
dispatchOnRequestFailed(reason);
}
+
+ @Override
+ public void onSessionUpdated(RoutingSessionInfo sessionInfo) {
+ dispatchDataChanged();
+ }
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 99c568a..734866f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -625,6 +625,15 @@
}
@Test
+ public void onSessionUpdated_shouldDispatchDataChanged() {
+ mInfoMediaManager.registerCallback(mCallback);
+
+ mInfoMediaManager.mMediaRouterCallback.onSessionUpdated(mock(RoutingSessionInfo.class));
+
+ verify(mCallback).onDeviceAttributesChanged();
+ }
+
+ @Test
public void addMediaDevice_verifyDeviceTypeCanCorrespondToMediaDevice() {
final MediaRoute2Info route2Info = mock(MediaRoute2Info.class);
final CachedBluetoothDeviceManager cachedBluetoothDeviceManager =
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
index 8bd7c79..30156a0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
@@ -58,7 +58,7 @@
*/
public void onReceive(Context context, Bundle bundle, View view, Size viewSize) {
if (mSurfaceControlViewHost != null) {
- mSurfaceControlViewHost.die();
+ mSurfaceControlViewHost.release();
}
SurfaceControl surfaceControl = SurfaceViewRequestUtils.getSurfaceControl(bundle);
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
index fa45ea1..1a53c28 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
@@ -134,7 +134,7 @@
private void setupTexture(Bitmap bitmap) {
final int[] tids = new int[1];
- if (bitmap == null) {
+ if (bitmap == null || bitmap.isRecycled()) {
Log.w(TAG, "setupTexture: invalid bitmap");
return;
}
@@ -146,16 +146,20 @@
return;
}
- // Bind a named texture to a target.
- glBindTexture(GL_TEXTURE_2D, tids[0]);
- // Load the bitmap data and copy it over into the texture object that is currently bound.
- GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
- // Use bilinear texture filtering when minification.
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- // Use bilinear texture filtering when magnification.
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- mTextureId = tids[0];
+ try {
+ // Bind a named texture to a target.
+ glBindTexture(GL_TEXTURE_2D, tids[0]);
+ // Load the bitmap data and copy it over into the texture object
+ // that is currently bound.
+ GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
+ // Use bilinear texture filtering when minification.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ // Use bilinear texture filtering when magnification.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ mTextureId = tids[0];
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Failed uploading texture: " + e.getLocalizedMessage());
+ }
}
void useTexture() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 0468373..e302fd7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -815,6 +815,7 @@
private class DefaultPipTouchGesture extends PipTouchGesture {
private final Point mStartPosition = new Point();
private final PointF mDelta = new PointF();
+ private boolean mShouldHideMenuAfterFling;
@Override
public void onDown(PipTouchState touchState) {
@@ -892,21 +893,17 @@
final float velocity = PointF.length(vel.x, vel.y);
if (touchState.isDragging()) {
- Runnable endAction = null;
if (mMenuState != MENU_STATE_NONE) {
// If the menu is still visible, then just poke the menu so that
// it will timeout after the user stops touching it
mMenuController.showMenu(mMenuState, mMotionHelper.getBounds(),
true /* allowMenuTimeout */, willResizeMenu());
- } else {
- // If the menu is not visible, then we can still be showing the activity for the
- // dismiss overlay, so just finish it after the animation completes
- endAction = mMenuController::hideMenu;
}
+ mShouldHideMenuAfterFling = mMenuState == MENU_STATE_NONE;
mMotionHelper.flingToSnapTarget(vel.x, vel.y,
PipTouchHandler.this::updateDismissFraction /* updateAction */,
- endAction /* endAction */);
+ this::flingEndAction /* endAction */);
} else if (mTouchState.isDoubleTap()) {
// Expand to fullscreen if this is a double tap
// the PiP should be frozen until the transition ends
@@ -927,6 +924,15 @@
}
return true;
}
+
+ private void flingEndAction() {
+ mTouchState.setAllowTouches(true);
+ if (mShouldHideMenuAfterFling) {
+ // If the menu is not visible, then we can still be showing the activity for the
+ // dismiss overlay, so just finish it after the animation completes
+ mMenuController.hideMenu();
+ }
+ }
};
/**
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 02a7aca..db33c79 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -592,13 +592,11 @@
removeDivider();
addDivider(configuration);
- if (mView != null) {
- if (mMinimized) {
- mView.setMinimizedDockStack(true, mHomeStackResizable);
- updateTouchable();
- }
- mView.setHidden(isDividerHidden);
+ if (mMinimized) {
+ mView.setMinimizedDockStack(true, mHomeStackResizable);
+ updateTouchable();
}
+ mView.setHidden(isDividerHidden);
}
void onTaskVanished() {
@@ -610,7 +608,7 @@
mContext.getDisplayId()).getResources().getConfiguration()));
}
- void updateVisibility(final boolean visible) {
+ private void updateVisibility(final boolean visible) {
if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible);
if (mVisible != visible) {
mVisible = visible;
@@ -639,6 +637,7 @@
void onSplitDismissed() {
mMinimized = false;
updateVisibility(false /* visible */);
+ removeDivider();
}
/** Switch to minimized state if appropriate */
@@ -788,6 +787,8 @@
}
void startEnterSplit() {
+ update(mDisplayController.getDisplayContext(
+ mContext.getDisplayId()).getResources().getConfiguration());
// Set resizable directly here because applyEnterSplit already resizes home stack.
mHomeStackResizable = WindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
index 2e4a929d..926c1bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
@@ -321,8 +321,7 @@
|| state.mPanelVisible || state.mKeyguardFadingAway || state.mBouncerShowing
|| state.mHeadsUpShowing
|| state.mScrimsVisibility != ScrimController.TRANSPARENT)
- || state.mBackgroundBlurRadius > 0
- || state.mLaunchingActivity;
+ || state.mBackgroundBlurRadius > 0;
}
private void applyFitsSystemWindows(State state) {
@@ -486,11 +485,6 @@
apply(mCurrentState);
}
- void setLaunchingActivity(boolean launching) {
- mCurrentState.mLaunchingActivity = launching;
- apply(mCurrentState);
- }
-
public void setScrimsVisibility(int scrimsVisibility) {
mCurrentState.mScrimsVisibility = scrimsVisibility;
apply(mCurrentState);
@@ -651,7 +645,6 @@
boolean mForceCollapsed;
boolean mForceDozeBrightness;
boolean mForceUserActivity;
- boolean mLaunchingActivity;
boolean mBackdropShowing;
boolean mWallpaperSupportsAmbientMode;
boolean mNotTouchable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 0d25898..596a607 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -93,7 +93,6 @@
private PhoneStatusBarView mStatusBarView;
private PhoneStatusBarTransitions mBarTransitions;
private StatusBar mService;
- private NotificationShadeWindowController mNotificationShadeWindowController;
private DragDownHelper mDragDownHelper;
private boolean mDoubleTapEnabled;
private boolean mSingleTapEnabled;
@@ -431,14 +430,10 @@
public void setExpandAnimationPending(boolean pending) {
mExpandAnimationPending = pending;
- mNotificationShadeWindowController
- .setLaunchingActivity(mExpandAnimationPending | mExpandAnimationRunning);
}
public void setExpandAnimationRunning(boolean running) {
mExpandAnimationRunning = running;
- mNotificationShadeWindowController
- .setLaunchingActivity(mExpandAnimationPending | mExpandAnimationRunning);
}
public void cancelExpandHelper() {
@@ -461,9 +456,8 @@
}
}
- public void setService(StatusBar statusBar, NotificationShadeWindowController controller) {
+ public void setService(StatusBar statusBar) {
mService = statusBar;
- mNotificationShadeWindowController = controller;
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index dd54a3d..bbf83bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1001,7 +1001,7 @@
updateTheme();
inflateStatusBarWindow();
- mNotificationShadeWindowViewController.setService(this, mNotificationShadeWindowController);
+ mNotificationShadeWindowViewController.setService(this);
mNotificationShadeWindowView.setOnTouchListener(getStatusBarWindowTouchListener());
// TODO: Deal with the ugliness that comes from having some of the statusbar broken out
diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
index 93f45c5..21f67ae 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
@@ -125,7 +125,7 @@
*/
public void removeView(View view) {
SurfaceControlViewHost root = mViewRoots.remove(view);
- root.die();
+ root.release();
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
index ca7a5db..8948fd0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
@@ -74,7 +74,7 @@
DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, "true", false)
assertTrue("People filtering should be enabled", manager!!.isFilteringEnabled())
- assertTrue("Expecting 4 buckets when people filtering is enabled",
- manager!!.getNumberOfBuckets() == 4)
+ assertTrue("Expecting 5 buckets when people filtering is enabled",
+ manager!!.getNumberOfBuckets() == 5)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index e04d25b..cc2d1c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -83,7 +83,6 @@
@Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
@Mock private NotificationShadeDepthController mNotificationShadeDepthController;
@Mock private SuperStatusBarViewFactory mStatusBarViewFactory;
- @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@Before
public void setUp() {
@@ -122,7 +121,7 @@
mNotificationPanelViewController,
mStatusBarViewFactory);
mController.setupExpandedStatusBar();
- mController.setService(mStatusBar, mNotificationShadeWindowController);
+ mController.setService(mStatusBar);
mController.setDragDownHelper(mDragDownHelper);
}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 2a5e620..04ad43f 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -109,8 +109,10 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceSpecificException;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -228,6 +230,7 @@
private final ConnectedClientsTracker mConnectedClientsTracker;
private final TetheringThreadExecutor mExecutor;
private final TetheringNotificationUpdater mNotificationUpdater;
+ private final UserManager mUserManager;
private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
// All the usage of mTetheringEventCallback should run in the same thread.
private ITetheringEventCallback mTetheringEventCallback = null;
@@ -305,23 +308,24 @@
mStateReceiver = new StateReceiver();
- final UserManager userManager = (UserManager) mContext.getSystemService(
- Context.USER_SERVICE);
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mTetheringRestriction = new UserRestrictionActionListener(
- userManager, this, mNotificationUpdater);
+ mUserManager, this, mNotificationUpdater);
mExecutor = new TetheringThreadExecutor(mHandler);
mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
mNetdCallback = new NetdCallback();
// Load tethering configuration.
updateConfiguration();
+
+ startStateMachineUpdaters();
}
/**
* Start to register callbacks.
* Call this function when tethering is ready to handle callback events.
*/
- public void startStateMachineUpdaters() {
+ private void startStateMachineUpdaters() {
try {
mNetd.registerUnsolicitedEventListener(mNetdCallback);
} catch (RemoteException e) {
@@ -779,7 +783,7 @@
// TODO: Figure out how to update for local hotspot mode interfaces.
private void sendTetherStateChangedBroadcast() {
- if (!mDeps.isTetheringSupported()) return;
+ if (!isTetheringSupported()) return;
final ArrayList<String> availableList = new ArrayList<>();
final ArrayList<String> tetherList = new ArrayList<>();
@@ -1020,14 +1024,14 @@
@VisibleForTesting
protected static class UserRestrictionActionListener {
- private final UserManager mUserManager;
+ private final UserManager mUserMgr;
private final Tethering mWrapper;
private final TetheringNotificationUpdater mNotificationUpdater;
public boolean mDisallowTethering;
public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper,
@NonNull TetheringNotificationUpdater updater) {
- mUserManager = um;
+ mUserMgr = um;
mWrapper = wrapper;
mNotificationUpdater = updater;
mDisallowTethering = false;
@@ -1037,7 +1041,7 @@
// getUserRestrictions gets restriction for this process' user, which is the primary
// user. This is fine because DISALLOW_CONFIG_TETHERING can only be set on the primary
// user. See UserManager.DISALLOW_CONFIG_TETHERING.
- final Bundle restrictions = mUserManager.getUserRestrictions();
+ final Bundle restrictions = mUserMgr.getUserRestrictions();
final boolean newlyDisallowed =
restrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
final boolean prevDisallowed = mDisallowTethering;
@@ -1988,7 +1992,7 @@
mHandler.post(() -> {
mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission));
final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
- parcel.tetheringSupported = mDeps.isTetheringSupported();
+ parcel.tetheringSupported = isTetheringSupported();
parcel.upstreamNetwork = mTetherUpstream;
parcel.config = mConfig.toStableParcelable();
parcel.states =
@@ -2111,6 +2115,20 @@
}
}
+ // if ro.tether.denied = true we default to no tethering
+ // gservices could set the secure setting to 1 though to enable it on a build where it
+ // had previously been turned off.
+ boolean isTetheringSupported() {
+ final int defaultVal =
+ SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1;
+ final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
+ final boolean tetherEnabledInSettings = tetherSupported
+ && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
+
+ return tetherEnabledInSettings && hasTetherableConfiguration();
+ }
+
void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
// Binder.java closes the resource for us.
@SuppressWarnings("resource")
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
index d07c555f..bf7fb04 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
@@ -40,15 +40,12 @@
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.ip.IpServer;
-import android.net.util.SharedLog;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.SystemProperties;
-import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
@@ -68,21 +65,14 @@
public class TetheringService extends Service {
private static final String TAG = TetheringService.class.getSimpleName();
- private final SharedLog mLog = new SharedLog(TAG);
private TetheringConnector mConnector;
- private Context mContext;
- private TetheringDependencies mDeps;
- private Tethering mTethering;
- private UserManager mUserManager;
@Override
public void onCreate() {
- mLog.mark("onCreate");
- mDeps = getTetheringDependencies();
- mContext = mDeps.getContext();
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- mTethering = makeTethering(mDeps);
- mTethering.startStateMachineUpdaters();
+ final TetheringDependencies deps = makeTetheringDependencies();
+ // The Tethering object needs a fully functional context to start, so this can't be done
+ // in the constructor.
+ mConnector = new TetheringConnector(makeTethering(deps), TetheringService.this);
}
/**
@@ -94,21 +84,10 @@
return new Tethering(deps);
}
- /**
- * Create a binder connector for the system server to communicate with the tethering.
- */
- private synchronized IBinder makeConnector() {
- if (mConnector == null) {
- mConnector = new TetheringConnector(mTethering, TetheringService.this);
- }
- return mConnector;
- }
-
@NonNull
@Override
public IBinder onBind(Intent intent) {
- mLog.mark("onBind");
- return makeConnector();
+ return mConnector;
}
private static class TetheringConnector extends ITetheringConnector.Stub {
@@ -237,7 +216,7 @@
listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
return true;
}
- if (!mService.isTetheringSupported()) {
+ if (!mTethering.isTetheringSupported()) {
listener.onResult(TETHER_ERROR_UNSUPPORTED);
return true;
}
@@ -253,7 +232,7 @@
receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
return true;
}
- if (!mService.isTetheringSupported()) {
+ if (!mTethering.isTetheringSupported()) {
receiver.send(TETHER_ERROR_UNSUPPORTED, null);
return true;
}
@@ -287,105 +266,83 @@
}
}
- // if ro.tether.denied = true we default to no tethering
- // gservices could set the secure setting to 1 though to enable it on a build where it
- // had previously been turned off.
- private boolean isTetheringSupported() {
- final int defaultVal =
- SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1;
- final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
- final boolean tetherEnabledInSettings = tetherSupported
- && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
-
- return tetherEnabledInSettings && mTethering.hasTetherableConfiguration();
- }
-
/**
* An injection method for testing.
*/
@VisibleForTesting
- public TetheringDependencies getTetheringDependencies() {
- if (mDeps == null) {
- mDeps = new TetheringDependencies() {
- @Override
- public NetworkRequest getDefaultNetworkRequest() {
- // TODO: b/147280869, add a proper system API to replace this.
- final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build();
- return trackDefaultRequest;
- }
+ public TetheringDependencies makeTetheringDependencies() {
+ return new TetheringDependencies() {
+ @Override
+ public NetworkRequest getDefaultNetworkRequest() {
+ // TODO: b/147280869, add a proper system API to replace this.
+ final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder()
+ .clearCapabilities()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
+ return trackDefaultRequest;
+ }
- @Override
- public Looper getTetheringLooper() {
- final HandlerThread tetherThread = new HandlerThread("android.tethering");
- tetherThread.start();
- return tetherThread.getLooper();
- }
+ @Override
+ public Looper getTetheringLooper() {
+ final HandlerThread tetherThread = new HandlerThread("android.tethering");
+ tetherThread.start();
+ return tetherThread.getLooper();
+ }
- @Override
- public boolean isTetheringSupported() {
- return TetheringService.this.isTetheringSupported();
- }
+ @Override
+ public Context getContext() {
+ return TetheringService.this;
+ }
- @Override
- public Context getContext() {
- return TetheringService.this;
- }
+ @Override
+ public IpServer.Dependencies getIpServerDependencies() {
+ return new IpServer.Dependencies() {
+ @Override
+ public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
+ DhcpServerCallbacks cb) {
+ try {
+ final INetworkStackConnector service = getNetworkStackConnector();
+ if (service == null) return;
- @Override
- public IpServer.Dependencies getIpServerDependencies() {
- return new IpServer.Dependencies() {
- @Override
- public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
- DhcpServerCallbacks cb) {
+ service.makeDhcpServer(ifName, params, cb);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Fail to make dhcp server");
try {
- final INetworkStackConnector service = getNetworkStackConnector();
- if (service == null) return;
-
- service.makeDhcpServer(ifName, params, cb);
- } catch (RemoteException e) {
- Log.e(TAG, "Fail to make dhcp server");
- try {
- cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null);
- } catch (RemoteException re) { }
- }
+ cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null);
+ } catch (RemoteException re) { }
}
- };
- }
-
- // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring
- // networkStackClient.
- static final int NETWORKSTACK_TIMEOUT_MS = 60_000;
- private INetworkStackConnector getNetworkStackConnector() {
- IBinder connector;
- try {
- final long before = System.currentTimeMillis();
- while ((connector = NetworkStack.getService()) == null) {
- if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
- Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector");
- return null;
- }
- Thread.sleep(200);
- }
- } catch (InterruptedException e) {
- Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector");
- return null;
}
- return INetworkStackConnector.Stub.asInterface(connector);
- }
+ };
+ }
- @Override
- public BluetoothAdapter getBluetoothAdapter() {
- return BluetoothAdapter.getDefaultAdapter();
+ // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring
+ // networkStackClient.
+ static final int NETWORKSTACK_TIMEOUT_MS = 60_000;
+ private INetworkStackConnector getNetworkStackConnector() {
+ IBinder connector;
+ try {
+ final long before = System.currentTimeMillis();
+ while ((connector = NetworkStack.getService()) == null) {
+ if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
+ Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector");
+ return null;
+ }
+ Thread.sleep(200);
+ }
+ } catch (InterruptedException e) {
+ Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector");
+ return null;
}
- };
- }
- return mDeps;
+ return INetworkStackConnector.Stub.asInterface(connector);
+ }
+
+ @Override
+ public BluetoothAdapter getBluetoothAdapter() {
+ return BluetoothAdapter.getDefaultAdapter();
+ }
+ };
}
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index 51bad9a..4a667b1 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -82,8 +82,7 @@
mTetheringConnector = mockConnector.getTetheringConnector();
final MockTetheringService service = mockConnector.getService();
mTethering = service.getTethering();
- verify(mTethering).startStateMachineUpdaters();
- when(mTethering.hasTetherableConfiguration()).thenReturn(true);
+ when(mTethering.isTetheringSupported()).thenReturn(true);
}
@After
@@ -96,7 +95,7 @@
when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).tether(TEST_IFACE_NAME);
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -107,7 +106,7 @@
when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).untether(TEST_IFACE_NAME);
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -118,7 +117,7 @@
when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR);
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).setUsbTethering(true /* enable */);
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -130,7 +129,7 @@
final TetheringRequestParcel request = new TetheringRequestParcel();
request.tetheringType = TETHERING_WIFI;
mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).startTethering(eq(request), eq(result));
verifyNoMoreInteractions(mTethering);
}
@@ -139,7 +138,7 @@
public void testStopTethering() throws Exception {
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).stopTethering(TETHERING_WIFI);
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -150,7 +149,7 @@
final ResultReceiver result = new ResultReceiver(null);
mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result,
true /* showEntitlementUi */, TEST_CALLER_PKG);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI),
eq(result), eq(true) /* showEntitlementUi */);
verifyNoMoreInteractions(mTethering);
@@ -177,7 +176,7 @@
public void testStopAllTethering() throws Exception {
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).untetherAll();
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -187,7 +186,7 @@
public void testIsTetheringSupported() throws Exception {
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 2bd8ae0..00174e6 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -485,18 +485,6 @@
MockitoAnnotations.initMocks(this);
when(mResources.getStringArray(R.array.config_tether_dhcp_range))
.thenReturn(new String[0]);
- when(mResources.getStringArray(R.array.config_tether_usb_regexs))
- .thenReturn(new String[] { "test_rndis\\d" });
- when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
- .thenReturn(new String[]{ "test_wlan\\d" });
- when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
- .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
- when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
- .thenReturn(new String[0]);
- when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
- .thenReturn(new String[] { "test_ncm\\d" });
- when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]);
- when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false);
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
false);
when(mNetd.interfaceGetList())
@@ -515,6 +503,7 @@
mServiceContext = new TestContext(mContext);
mContentResolver = new MockContentResolver(mServiceContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ setTetheringSupported(true /* supported */);
mIntents = new Vector<>();
mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -525,7 +514,6 @@
mServiceContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(ACTION_TETHER_STATE_CHANGED));
mTethering = makeTethering();
- mTethering.startStateMachineUpdaters();
verify(mStatsManager, times(1)).registerNetworkStatsProvider(anyString(), any());
verify(mNetd).registerUnsolicitedEventListener(any());
final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor =
@@ -536,6 +524,31 @@
mPhoneStateListener = phoneListenerCaptor.getValue();
}
+ private void setTetheringSupported(final boolean supported) {
+ Settings.Global.putInt(mContentResolver, Settings.Global.TETHER_SUPPORTED,
+ supported ? 1 : 0);
+ when(mUserManager.hasUserRestriction(
+ UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(!supported);
+ // Setup tetherable configuration.
+ when(mResources.getStringArray(R.array.config_tether_usb_regexs))
+ .thenReturn(new String[] { "test_rndis\\d" });
+ when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
+ .thenReturn(new String[]{ "test_wlan\\d" });
+ when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
+ .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
+ when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
+ .thenReturn(new String[0]);
+ when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
+ .thenReturn(new String[] { "test_ncm\\d" });
+ when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]);
+ when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(true);
+ }
+
+ private void initTetheringUpstream(UpstreamNetworkState upstreamState) {
+ when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
+ when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState);
+ }
+
private Tethering makeTethering() {
mTetheringDependencies.reset();
return new Tethering(mTetheringDependencies);
@@ -672,9 +685,7 @@
}
private void prepareUsbTethering(UpstreamNetworkState upstreamState) {
- when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
- .thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
// Emulate pressing the USB tethering button in Settings UI.
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), null);
@@ -700,7 +711,7 @@
verify(mNetd, times(1)).interfaceGetList();
// UpstreamNetworkMonitor should receive selected upstream
- verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any());
+ verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream();
verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
}
@@ -872,8 +883,7 @@
// Then 464xlat comes up
upstreamState = buildMobile464xlatUpstreamState();
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
- .thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
// Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
@@ -1344,9 +1354,7 @@
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
// 2. Enable wifi tethering.
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
- when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
- .thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
mLooper.dispatchAll();
@@ -1723,7 +1731,7 @@
final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
stateMachine.chooseUpstreamType(true);
verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(eq(upstreamState.network));
@@ -1735,7 +1743,7 @@
final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
stateMachine.chooseUpstreamType(true);
stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState);
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
index a14584a..4b89731 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
@@ -20,9 +20,9 @@
import static com.android.server.accessibility.gestures.GestureUtils.MM_PER_CM;
import static com.android.server.accessibility.gestures.GestureUtils.getActionIndex;
-import static com.android.server.accessibility.gestures.Swipe.CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS;
-import static com.android.server.accessibility.gestures.Swipe.CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS;
import static com.android.server.accessibility.gestures.Swipe.GESTURE_CONFIRM_CM;
+import static com.android.server.accessibility.gestures.Swipe.MAX_TIME_TO_CONTINUE_SWIPE_MS;
+import static com.android.server.accessibility.gestures.Swipe.MAX_TIME_TO_START_SWIPE_MS;
import static com.android.server.accessibility.gestures.TouchExplorer.DEBUG;
import android.content.Context;
@@ -387,10 +387,10 @@
cancelPendingTransitions();
switch (getState()) {
case STATE_CLEAR:
- cancelAfter(CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS, event, rawEvent, policyFlags);
+ cancelAfter(MAX_TIME_TO_START_SWIPE_MS, event, rawEvent, policyFlags);
break;
case STATE_GESTURE_STARTED:
- cancelAfter(CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS, event, rawEvent, policyFlags);
+ cancelAfter(MAX_TIME_TO_CONTINUE_SWIPE_MS, event, rawEvent, policyFlags);
break;
default:
break;
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
index 9108c69..041b424 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
@@ -49,11 +49,10 @@
// Buffer for storing points for gesture detection.
private final ArrayList<PointF> mStrokeBuffer = new ArrayList<>(100);
- // The minimal delta between moves to add a gesture point.
- private static final int TOUCH_TOLERANCE_PIX = 3;
-
- // The minimal score for accepting a predicted gesture.
- private static final float MIN_PREDICTION_SCORE = 2.0f;
+ // Constants for sampling motion event points.
+ // We sample based on a minimum distance between points, primarily to improve accuracy by
+ // reducing noisy minor changes in direction.
+ private static final float MIN_CM_BETWEEN_SAMPLES = 0.25f;
// Distance a finger must travel before we decide if it is a gesture or not.
public static final int GESTURE_CONFIRM_CM = 1;
@@ -67,22 +66,19 @@
// all gestures started with the initial movement taking less than 100ms.
// When touch exploring, the first movement almost always takes longer than
// 200ms.
- public static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 150;
+ public static final long MAX_TIME_TO_START_SWIPE_MS = 150 * GESTURE_CONFIRM_CM;
// Time threshold used to determine if a gesture should be cancelled. If
- // the finger takes more than this time to move 1cm, the ongoing gesture is
- // cancelled.
- public static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 300;
+ // the finger takes more than this time to move to the next sample point, the ongoing gesture
+ // is cancelled.
+ public static final long MAX_TIME_TO_CONTINUE_SWIPE_MS = 350 * GESTURE_CONFIRM_CM;
private int[] mDirections;
private float mBaseX;
private float mBaseY;
+ private long mBaseTime;
private float mPreviousGestureX;
private float mPreviousGestureY;
- // Constants for sampling motion event points.
- // We sample based on a minimum distance between points, primarily to improve accuracy by
- // reducing noisy minor changes in direction.
- private static final float MIN_CM_BETWEEN_SAMPLES = 0.25f;
private final float mMinPixelsBetweenSamplesX;
private final float mMinPixelsBetweenSamplesY;
// The minmimum distance the finger must travel before we evaluate the initial direction of the
@@ -134,16 +130,19 @@
protected void clear() {
mBaseX = Float.NaN;
mBaseY = Float.NaN;
+ mBaseTime = 0;
+ mPreviousGestureX = Float.NaN;
+ mPreviousGestureY = Float.NaN;
mStrokeBuffer.clear();
super.clear();
}
@Override
protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- cancelAfterPauseThreshold(event, rawEvent, policyFlags);
if (Float.isNaN(mBaseX) && Float.isNaN(mBaseY)) {
mBaseX = rawEvent.getX();
mBaseY = rawEvent.getY();
+ mBaseTime = rawEvent.getEventTime();
mPreviousGestureX = mBaseX;
mPreviousGestureY = mBaseY;
}
@@ -154,9 +153,11 @@
protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
final float x = rawEvent.getX();
final float y = rawEvent.getY();
+ final long time = rawEvent.getEventTime();
final float dX = Math.abs(x - mPreviousGestureX);
final float dY = Math.abs(y - mPreviousGestureY);
final double moveDelta = Math.hypot(Math.abs(x - mBaseX), Math.abs(y - mBaseY));
+ final long timeDelta = time - mBaseTime;
if (DEBUG) {
Slog.d(
getGestureName(),
@@ -171,34 +172,38 @@
return;
} else if (mStrokeBuffer.size() == 0) {
// First, make sure the pointer is going in the right direction.
- cancelAfterPauseThreshold(event, rawEvent, policyFlags);
int direction = toDirection(x - mBaseX, y - mBaseY);
if (direction != mDirections[0]) {
cancelGesture(event, rawEvent, policyFlags);
return;
- } else {
- // This is confirmed to be some kind of swipe so start tracking points.
- mStrokeBuffer.add(new PointF(mBaseX, mBaseY));
}
- }
- if (moveDelta > mGestureDetectionThresholdPixels) {
- // If the pointer has moved more than the threshold,
- // update the stored values.
- mBaseX = x;
- mBaseY = y;
- if (getState() == STATE_CLEAR) {
- startGesture(event, rawEvent, policyFlags);
- cancelAfterPauseThreshold(event, rawEvent, policyFlags);
- }
+ // This is confirmed to be some kind of swipe so start tracking points.
+ mStrokeBuffer.add(new PointF(mBaseX, mBaseY));
}
}
- if (getState() == STATE_GESTURE_STARTED) {
- if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
- mPreviousGestureX = x;
- mPreviousGestureY = y;
- mStrokeBuffer.add(new PointF(x, y));
- cancelAfterPauseThreshold(event, rawEvent, policyFlags);
+ if (moveDelta > mGestureDetectionThresholdPixels) {
+ // This is a gesture, not touch exploration.
+ mBaseX = x;
+ mBaseY = y;
+ mBaseTime = time;
+ startGesture(event, rawEvent, policyFlags);
+ } else if (getState() == STATE_CLEAR) {
+ if (timeDelta > MAX_TIME_TO_START_SWIPE_MS) {
+ // The user isn't moving fast enough.
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
}
+ } else if (getState() == STATE_GESTURE_STARTED) {
+ if (timeDelta > MAX_TIME_TO_CONTINUE_SWIPE_MS) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ }
+ if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
+ // At this point gesture detection has started and we are sampling points.
+ mPreviousGestureX = x;
+ mPreviousGestureY = y;
+ mStrokeBuffer.add(new PointF(x, y));
}
}
@@ -230,25 +235,6 @@
}
/**
- * queues a transition to STATE_GESTURE_CANCEL based on the current state. If we have
- * transitioned to STATE_GESTURE_STARTED the delay is longer.
- */
- private void cancelAfterPauseThreshold(
- MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- cancelPendingTransitions();
- switch (getState()) {
- case STATE_CLEAR:
- cancelAfter(CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS, event, rawEvent, policyFlags);
- break;
- case STATE_GESTURE_STARTED:
- cancelAfter(CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS, event, rawEvent, policyFlags);
- break;
- default:
- break;
- }
- }
-
- /**
* Looks at the sequence of motions in mStrokeBuffer, classifies the gesture, then calls
* Listener callbacks for success or failure.
*
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
index 3282870..3dd2433 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
@@ -67,8 +67,8 @@
* Requests the IME to create an {@link InlineSuggestionsRequest} for {@code autofillId}.
*
* @param autofillId the Id of the field for which the request is for.
- * @param requestConsumer the callback which will be invoked when IME responded or if it times
- * out waiting for IME response.
+ * @param requestConsumer the callback to be invoked when the IME responds. Note that this is
+ * never invoked if the IME doesn't respond.
*/
@GuardedBy("mLock")
void onCreateInlineSuggestionsRequestLocked(@NonNull AutofillId autofillId,
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index 0bf8993..1a3baba 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -55,16 +55,6 @@
private static final String TAG = AutofillInlineSuggestionsRequestSession.class.getSimpleName();
- // This timeout controls how long Autofill should wait for the IME to respond either
- // unsupported or an {@link InlineSuggestionsRequest}. The timeout is needed to take into
- // account the latency between the two events after a field is focused, 1) an Autofill
- // request is triggered on framework; 2) the InputMethodService#onStartInput() event is
- // triggered on the IME side. When 1) happens, Autofill may call the IME to return an {@link
- // InlineSuggestionsRequest}, but the IME will only return it after 2) happens (or return
- // immediately if the IME doesn't support inline suggestions). Also there is IPC latency
- // between the framework and the IME but that should be small compare to that.
- private static final int CREATE_INLINE_SUGGESTIONS_REQUEST_TIMEOUT_MS = 1000;
-
@NonNull
private final InputMethodManagerInternal mInputMethodManagerInternal;
private final int mUserId;
@@ -92,9 +82,6 @@
@GuardedBy("mLock")
@Nullable
private IInlineSuggestionsResponseCallback mResponseCallback;
- @GuardedBy("mLock")
- @Nullable
- private Runnable mTimeoutCallback;
@GuardedBy("mLock")
@Nullable
@@ -174,12 +161,17 @@
}
/**
- * This method must be called when the session is destroyed, to avoid further callbacks from/to
- * the IME.
+ * Prevents further interaction with the IME. Must be called before starting a new request
+ * session to avoid unwanted behavior from two overlapping requests.
*/
@GuardedBy("mLock")
void destroySessionLocked() {
mDestroyed = true;
+
+ if (!mImeRequestReceived) {
+ Slog.w(TAG,
+ "Never received an InlineSuggestionsRequest from the IME for " + mAutofillId);
+ }
}
/**
@@ -196,11 +188,6 @@
mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(mUserId,
new InlineSuggestionsRequestInfo(mComponentName, mAutofillId, mUiExtras),
new InlineSuggestionsRequestCallbackImpl(this));
- mTimeoutCallback = () -> {
- Slog.w(TAG, "Timed out waiting for IME callback InlineSuggestionsRequest.");
- handleOnReceiveImeRequest(null, null);
- };
- mHandler.postDelayed(mTimeoutCallback, CREATE_INLINE_SUGGESTIONS_REQUEST_TIMEOUT_MS);
}
/**
@@ -212,12 +199,12 @@
if (mDestroyed || mResponseCallback == null) {
return;
}
- if (!mImeInputViewStarted && mPreviousResponseIsNotEmpty) {
- // 1. if previous response is not empty, and IME just become invisible, then send
- // empty response to make sure existing responses don't stick around on the IME.
+ if (!mImeInputStarted && mPreviousResponseIsNotEmpty) {
+ // 1. if previous response is not empty, and IME is just disconnected from the view,
+ // then send empty response to make sure existing responses don't stick around.
// Although the inline suggestions should disappear when IME hides which removes them
- // from the view hierarchy, but we still send an empty response to be extra safe.
-
+ // from the view hierarchy, but we still send an empty response to indicate that the
+ // previous suggestions are invalid now.
if (sVerbose) Slog.v(TAG, "Send empty inline response");
updateResponseToImeUncheckLocked(new InlineSuggestionsResponse(Collections.EMPTY_LIST));
mPreviousResponseIsNotEmpty = false;
@@ -264,11 +251,6 @@
}
mImeRequestReceived = true;
- if (mTimeoutCallback != null) {
- if (sVerbose) Slog.v(TAG, "removing timeout callback");
- mHandler.removeCallbacks(mTimeoutCallback);
- mTimeoutCallback = null;
- }
if (request != null && callback != null) {
mImeRequest = request;
mResponseCallback = callback;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index ef17d13..1d3ab9b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2581,7 +2581,6 @@
if (sVerbose) Slog.v(TAG, "Exiting view " + id);
mUi.hideFillUi(this);
hideAugmentedAutofillLocked(viewState);
- mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
mCurrentViewId = null;
}
break;
@@ -2655,6 +2654,9 @@
if (sVerbose) {
Slog.v(TAG, "ignoring autofilled change on id " + id);
}
+ // TODO(b/156099633): remove this once framework gets out of business of resending
+ // inline suggestions when IME visibility changes.
+ mInlineSessionController.hideInlineSuggestionsUiLocked(viewState.id);
viewState.resetState(ViewState.STATE_CHANGED);
return;
} else if ((viewState.id.equals(this.mCurrentViewId))
@@ -3348,7 +3350,9 @@
if (generateEvent) {
mService.logDatasetSelected(dataset.getId(), id, mClientState);
}
-
+ if (mCurrentViewId != null) {
+ mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
+ }
autoFillApp(dataset);
return;
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index 089eeb2..8cc0de4 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -57,7 +57,6 @@
@NonNull AutoFillUI.AutoFillUiCallback client, @NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
final BiConsumer<Dataset, Integer> onClickFactory = (dataset, datasetIndex) -> {
- client.requestHideFillUi(autofillId);
client.authenticate(response.getRequestId(),
datasetIndex, response.getAuthentication(), response.getClientState(),
/* authenticateInline= */ true);
@@ -85,7 +84,6 @@
final Consumer<IntentSender> intentSenderConsumer = (intentSender) ->
client.startIntentSender(intentSender, new Intent());
final BiConsumer<Dataset, Integer> onClickFactory = (dataset, datasetIndex) -> {
- client.requestHideFillUi(autofillId);
client.fill(requestId, datasetIndex, dataset);
};
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index d49d4b2..de13bd8 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -45,6 +45,12 @@
}
/**
+ * Called by the power manager to tell the input method manager whether it
+ * should start watching for wake events.
+ */
+ public abstract void setInteractive(boolean interactive);
+
+ /**
* Hides the current input method, if visible.
*/
public abstract void hideCurrentInputMethod(@SoftInputShowHideReason int reason);
@@ -108,6 +114,10 @@
private static final InputMethodManagerInternal NOP =
new InputMethodManagerInternal() {
@Override
+ public void setInteractive(boolean interactive) {
+ }
+
+ @Override
public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) {
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index b949d6b..6efc88e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -4202,6 +4202,9 @@
+ ((ClientState)msg.obj).uid);
}
return true;
+ case MSG_SET_INTERACTIVE:
+ handleSetInteractive(msg.arg1 != 0);
+ return true;
case MSG_REPORT_FULLSCREEN_MODE: {
final boolean fullscreen = msg.arg1 != 0;
final ClientState clientState = (ClientState)msg.obj;
@@ -4276,6 +4279,20 @@
return false;
}
+ private void handleSetInteractive(final boolean interactive) {
+ synchronized (mMethodMap) {
+ mIsInteractive = interactive;
+ updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
+
+ // Inform the current client of the change in active status
+ if (mCurClient != null && mCurClient.client != null) {
+ executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
+ MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
+ mCurClient));
+ }
+ }
+ }
+
private boolean chooseNewDefaultIMELocked() {
final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
mSettings.getEnabledInputMethodListLocked());
@@ -4885,6 +4902,13 @@
}
@Override
+ public void setInteractive(boolean interactive) {
+ // Do everything in handler so as not to block the caller.
+ mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
+ .sendToTarget();
+ }
+
+ @Override
public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) {
mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
mService.mHandler.obtainMessage(MSG_HIDE_CURRENT_INPUT_METHOD, reason).sendToTarget();
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 0b73e4f..2129e9b 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -171,6 +171,11 @@
LocalServices.addService(InputMethodManagerInternal.class,
new InputMethodManagerInternal() {
@Override
+ public void setInteractive(boolean interactive) {
+ reportNotSupported();
+ }
+
+ @Override
public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) {
reportNotSupported();
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 199cb49..0b95be1 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -413,6 +413,7 @@
// Start input as soon as we start waking up or going to sleep.
mInputManagerInternal.setInteractive(interactive);
+ mInputMethodManagerInternal.setInteractive(interactive);
// Notify battery stats.
try {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 63952b0..31fbaff 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2743,7 +2743,7 @@
mContext, 0,
Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
- 0, null, new UserHandle(serviceUserId)));
+ PendingIntent.FLAG_IMMUTABLE, null, new UserHandle(serviceUserId)));
if (!mContext.bindServiceAsUser(intent, newConn,
Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
| Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 131e449..c079bd5 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1705,7 +1705,7 @@
boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
+ boolean allowTaskSnapshot, boolean activityCreated) {
// If the display is frozen, we won't do anything until the actual window is
// displayed so there is no reason to put in the starting window.
if (!okToDisplay()) {
@@ -1726,7 +1726,7 @@
mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId,
false /* restoreFromDisk */, false /* isLowResolution */);
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
- allowTaskSnapshot, activityCreated, fromRecents, snapshot);
+ allowTaskSnapshot, activityCreated, snapshot);
if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
if (isActivityTypeHome()) {
@@ -1888,12 +1888,12 @@
private final AddStartingWindow mAddStartingWindow = new AddStartingWindow();
private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
+ boolean allowTaskSnapshot, boolean activityCreated,
ActivityManager.TaskSnapshot snapshot) {
if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else if (taskSwitch && allowTaskSnapshot) {
- if (snapshotOrientationSameAsTask(snapshot) || (snapshot != null && fromRecents)) {
+ if (isSnapshotCompatible(snapshot)) {
return STARTING_WINDOW_TYPE_SNAPSHOT;
}
if (!isActivityTypeHome()) {
@@ -1905,11 +1905,22 @@
}
}
- private boolean snapshotOrientationSameAsTask(ActivityManager.TaskSnapshot snapshot) {
+ /**
+ * Returns {@code true} if the task snapshot is compatible with this activity (at least the
+ * rotation must be the same).
+ */
+ @VisibleForTesting
+ boolean isSnapshotCompatible(ActivityManager.TaskSnapshot snapshot) {
if (snapshot == null) {
return false;
}
- return task.getConfiguration().orientation == snapshot.getOrientation();
+ final int rotation = mDisplayContent.rotationForActivityInDifferentOrientation(this);
+ final int targetRotation = rotation != ROTATION_UNDEFINED
+ // The display may rotate according to the orientation of this activity.
+ ? rotation
+ // The activity won't change display orientation.
+ : task.getWindowConfiguration().getRotation();
+ return snapshot.getRotation() == targetRotation;
}
void removeStartingWindow() {
@@ -1929,7 +1940,6 @@
mStartingData = null;
startingSurface = null;
startingWindow = null;
- startingDisplayed = false;
if (surface == null) {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
"startingWindow was set but startingSurface==null, couldn't "
@@ -4785,16 +4795,7 @@
if (!task.hasChild(this)) {
throw new IllegalStateException("Activity not found in its task");
}
- final ActivityRecord activityAbove = task.getActivityAbove(this);
- if (activityAbove == null) {
- // It's the topmost activity in the task - should become resumed now
- return true;
- }
- // Check if activity above is finishing now and this one becomes the topmost in task.
- if (activityAbove.finishing) {
- return true;
- }
- return false;
+ return task.topRunningActivity() == this;
}
void handleAlreadyVisible() {
@@ -5453,7 +5454,6 @@
if (mLastTransactionSequence != mWmService.mTransactionSequence) {
mLastTransactionSequence = mWmService.mTransactionSequence;
mNumDrawnWindows = 0;
- startingDisplayed = false;
// There is the main base application window, even if it is exiting, wait for it
mNumInterestingWindows = findMainWindow(false /* includeStartingApp */) != null ? 1 : 0;
@@ -5673,11 +5673,6 @@
}
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) {
- showStartingWindow(prev, newTask, taskSwitch, false /* fromRecents */);
- }
-
- void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
- boolean fromRecents) {
if (mTaskOverlay) {
// We don't show starting window for overlay activities.
return;
@@ -5694,8 +5689,7 @@
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
allowTaskSnapshot(),
- mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
- fromRecents);
+ mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal());
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index dca0860..cb2d98c 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -1307,17 +1307,8 @@
/**
* Make sure that all activities that need to be visible in the stack (that is, they
* currently can be seen by the user) actually are and update their configuration.
- * @param starting The top most activity in the task.
- * The activity is either starting or resuming.
- * Caller should ensure starting activity is visible.
- * @param preserveWindows Flag indicating whether windows should be preserved when updating
- * configuration in {@link mEnsureActivitiesVisibleHelper}.
- * @param configChanges Parts of the configuration that changed for this activity for evaluating
- * if the screen should be frozen as part of
- * {@link mEnsureActivitiesVisibleHelper}.
- *
*/
- void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
+ void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows) {
ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */);
}
@@ -1326,19 +1317,9 @@
* Ensure visibility with an option to also update the configuration of visible activities.
* @see #ensureActivitiesVisible(ActivityRecord, int, boolean)
* @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean)
- * @param starting The top most activity in the task.
- * The activity is either starting or resuming.
- * Caller should ensure starting activity is visible.
- * @param notifyClients Flag indicating whether the visibility updates should be sent to the
- * clients in {@link mEnsureActivitiesVisibleHelper}.
- * @param preserveWindows Flag indicating whether windows should be preserved when updating
- * configuration in {@link mEnsureActivitiesVisibleHelper}.
- * @param configChanges Parts of the configuration that changed for this activity for evaluating
- * if the screen should be frozen as part of
- * {@link mEnsureActivitiesVisibleHelper}.
*/
// TODO: Should be re-worked based on the fact that each task as a stack in most cases.
- void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
+ void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients) {
mTopActivityOccludesKeyguard = false;
mTopDismissingKeyguardActivity = null;
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 3e7e0c8..62979ff 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2498,7 +2498,7 @@
mActivityMetricsLogger.notifyActivityLaunching(task.intent);
try {
mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */,
- task.mTaskId, 0, options, true /* fromRecents */);
+ task.mTaskId, 0, options);
// Apply options to prevent pendingOptions be taken by client to make sure
// the override pending app transition will be applied immediately.
targetActivity.applyOptionsLocked();
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index bcdd6e3..79e8ee3 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1539,10 +1539,7 @@
*
* Note: This method should only be called from {@link #startActivityUnchecked}.
*/
-
- // TODO(b/152429287): Make it easier to exercise code paths through startActivityInner
- @VisibleForTesting
- int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
+ private int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity) {
@@ -1663,10 +1660,7 @@
// Also, we don't want to resume activities in a task that currently has an overlay
// as the starting activity just needs to be in the visible paused state until the
// over is removed.
- // Passing {@code null} as the start parameter ensures all activities are made
- // visible.
- mTargetStack.ensureActivitiesVisible(null /* starting */,
- 0 /* configChanges */, !PRESERVE_WINDOWS);
+ mTargetStack.ensureActivitiesVisible(mStartActivity, 0, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f21ec6b..78e4237 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2476,13 +2476,12 @@
if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
synchronized (mGlobalLock) {
moveTaskToFrontLocked(appThread, callingPackage, taskId, flags,
- SafeActivityOptions.fromBundle(bOptions), false /* fromRecents */);
+ SafeActivityOptions.fromBundle(bOptions));
}
}
void moveTaskToFrontLocked(@Nullable IApplicationThread appThread,
- @Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options,
- boolean fromRecents) {
+ @Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
assertPackageMatchesCallingUid(callingPackage);
@@ -2527,7 +2526,7 @@
// We are reshowing a task, use a starting window to hide the initial draw delay
// so the transition can start earlier.
topActivity.showStartingWindow(null /* prev */, false /* newTask */,
- true /* taskSwitch */, fromRecents);
+ true /* taskSwitch */);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -3213,7 +3212,7 @@
if (TextUtils.equals(pae.intent.getAction(),
android.service.voice.VoiceInteractionService.SERVICE_INTERFACE)) {
// Start voice interaction through VoiceInteractionManagerService.
- mAssistUtils.showSessionForActiveService(sendBundle, SHOW_SOURCE_APPLICATION,
+ mAssistUtils.showSessionForActiveService(pae.extras, SHOW_SOURCE_APPLICATION,
null, null);
} else {
pae.intent.replaceExtras(pae.extras);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6655e92..3acb127 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -235,7 +235,6 @@
implements WindowManagerPolicy.DisplayContentInfo {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayContent" : TAG_WM;
private static final String TAG_STACK = TAG + POSTFIX_STACK;
- private static final int NO_ROTATION = -1;
/** The default scaling mode that scales content automatically. */
static final int FORCE_SCALING_MODE_AUTO = 0;
@@ -1394,36 +1393,40 @@
final WindowContainer orientationSource = getLastOrientationSource();
final ActivityRecord r =
orientationSource != null ? orientationSource.asActivityRecord() : null;
- if (r != null && r.getTask() != null
- && orientation != r.getTask().mLastReportedRequestedOrientation) {
+ if (r != null) {
final Task task = r.getTask();
- task.mLastReportedRequestedOrientation = orientation;
- mAtmService.getTaskChangeNotificationController()
- .notifyTaskRequestedOrientationChanged(task.mTaskId, orientation);
- }
- // Currently there is no use case from non-activity.
- if (r != null && handleTopActivityLaunchingInDifferentOrientation(r)) {
- // Display orientation should be deferred until the top fixed rotation is finished.
- return false;
+ if (task != null && orientation != task.mLastReportedRequestedOrientation) {
+ task.mLastReportedRequestedOrientation = orientation;
+ mAtmService.getTaskChangeNotificationController()
+ .notifyTaskRequestedOrientationChanged(task.mTaskId, orientation);
+ }
+ // Currently there is no use case from non-activity.
+ if (handleTopActivityLaunchingInDifferentOrientation(r, true /* checkOpening */)) {
+ // Display orientation should be deferred until the top fixed rotation is finished.
+ return false;
+ }
}
return mDisplayRotation.updateOrientation(orientation, forceUpdate);
}
- /** @return a valid rotation if the activity can use different orientation than the display. */
+ /**
+ * Returns a valid rotation if the activity can use different orientation than the display.
+ * Otherwise {@link #ROTATION_UNDEFINED}.
+ */
@Surface.Rotation
- private int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
+ int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
if (!mWmService.mIsFixedRotationTransformEnabled) {
- return NO_ROTATION;
+ return ROTATION_UNDEFINED;
}
if (r.inMultiWindowMode()
|| r.getRequestedConfigurationOrientation() == getConfiguration().orientation) {
- return NO_ROTATION;
+ return ROTATION_UNDEFINED;
}
final int currentRotation = getRotation();
final int rotation = mDisplayRotation.rotationForOrientation(r.getRequestedOrientation(),
currentRotation);
if (rotation == currentRotation) {
- return NO_ROTATION;
+ return ROTATION_UNDEFINED;
}
return rotation;
}
@@ -1433,9 +1436,13 @@
* is launching until the launch animation is done to avoid showing the previous activity
* inadvertently in a wrong orientation.
*
+ * @param r The launching activity which may change display orientation.
+ * @param checkOpening Whether to check if the activity is animating by transition. Set to
+ * {@code true} if the caller is not sure whether the activity is launching.
* @return {@code true} if the fixed rotation is started.
*/
- private boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r) {
+ boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r,
+ boolean checkOpening) {
if (!mWmService.mIsFixedRotationTransformEnabled) {
return false;
}
@@ -1446,19 +1453,18 @@
// It has been set and not yet finished.
return true;
}
- if (!mAppTransition.isTransitionSet()) {
- // Apply normal rotation animation in case of the activity set different requested
- // orientation without activity switch.
- return false;
- }
- if (!mOpeningApps.contains(r)
- // Without screen rotation, the rotation behavior of non-top visible activities is
- // undefined. So the fixed rotated activity needs to cover the screen.
- && r.findMainWindow() != mDisplayPolicy.getTopFullscreenOpaqueWindow()) {
+ if (checkOpening) {
+ if (!mAppTransition.isTransitionSet() && !mOpeningApps.contains(r)) {
+ // Apply normal rotation animation in case of the activity set different requested
+ // orientation without activity switch.
+ return false;
+ }
+ } else if (r != topRunningActivity()) {
+ // If the transition has not started yet, the activity must be the top.
return false;
}
final int rotation = rotationForActivityInDifferentOrientation(r);
- if (rotation == NO_ROTATION) {
+ if (rotation == ROTATION_UNDEFINED) {
return false;
}
if (!r.getParent().matchParentBounds()) {
@@ -1511,6 +1517,10 @@
sendNewConfiguration();
return;
}
+ if (mDisplayRotation.isWaitingForRemoteRotation()) {
+ // There is pending rotation change to apply.
+ return;
+ }
// The orientation of display is not changed.
clearFixedRotationLaunchingApp();
}
@@ -1551,7 +1561,7 @@
*/
void rotateInDifferentOrientationIfNeeded(ActivityRecord activityRecord) {
int rotation = rotationForActivityInDifferentOrientation(activityRecord);
- if (rotation != NO_ROTATION) {
+ if (rotation != ROTATION_UNDEFINED) {
startFixedRotationTransform(activityRecord, rotation);
}
}
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 9bbd4cd..5a24847 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -135,6 +135,7 @@
final int mOwnerPid;
final WindowManagerService mWmService;
InputChannel mInputChannel;
+ final int mWindowType;
/**
* @param clientToken client token used to clean up the map if the embedding process dies
@@ -146,7 +147,7 @@
* @param ownerPid calling pid used for anr blaming
*/
EmbeddedWindow(WindowManagerService service, IWindow clientToken,
- WindowState hostWindowState, int ownerUid, int ownerPid) {
+ WindowState hostWindowState, int ownerUid, int ownerPid, int windowType) {
mWmService = service;
mClient = clientToken;
mHostWindowState = hostWindowState;
@@ -154,6 +155,7 @@
: null;
mOwnerUid = ownerUid;
mOwnerPid = ownerPid;
+ mWindowType = windowType;
}
String getName() {
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index c4e03f5..c92de2b 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -21,7 +21,6 @@
import static com.android.server.wm.ActivityStack.TAG_VISIBILITY;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
-import android.annotation.Nullable;
import android.util.Slog;
import com.android.internal.util.function.pooled.PooledConsumer;
@@ -43,16 +42,6 @@
mContiner = container;
}
- /**
- * Update all attributes except {@link mContiner} to use in subsequent calculations.
- *
- * @param starting The activity that is being started
- * @param configChanges Parts of the configuration that changed for this activity for evaluating
- * if the screen should be frozen.
- * @param preserveWindows Flag indicating whether windows should be preserved when updating.
- * @param notifyClients Flag indicating whether the configuration and visibility changes shoulc
- * be sent to the clients.
- */
void reset(ActivityRecord starting, int configChanges, boolean preserveWindows,
boolean notifyClients) {
mStarting = starting;
@@ -71,17 +60,8 @@
* Ensure visibility with an option to also update the configuration of visible activities.
* @see ActivityStack#ensureActivitiesVisible(ActivityRecord, int, boolean)
* @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean)
- * @param starting The top most activity in the task.
- * The activity is either starting or resuming.
- * Caller should ensure starting activity is visible.
- *
- * @param configChanges Parts of the configuration that changed for this activity for evaluating
- * if the screen should be frozen.
- * @param preserveWindows Flag indicating whether windows should be preserved when updating.
- * @param notifyClients Flag indicating whether the configuration and visibility changes shoulc
- * be sent to the clients.
*/
- void process(@Nullable ActivityRecord starting, int configChanges, boolean preserveWindows,
+ void process(ActivityRecord starting, int configChanges, boolean preserveWindows,
boolean notifyClients) {
reset(starting, configChanges, preserveWindows, notifyClients);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index bf20cb9..6f5c440 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -661,17 +661,23 @@
@Override
public void grantInputChannel(int displayId, SurfaceControl surface,
- IWindow window, IBinder hostInputToken, int flags, InputChannel outInputChannel) {
+ IWindow window, IBinder hostInputToken, int flags, int type,
+ InputChannel outInputChannel) {
if (hostInputToken == null && !mCanAddInternalSystemWindow) {
// Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to
// embedded windows without providing a host window input token
throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
}
+ if (!mCanAddInternalSystemWindow && type != 0) {
+ Slog.w(TAG_WM, "Requires INTERNAL_SYSTEM_WINDOW permission if assign type to"
+ + " input");
+ }
+
final long identity = Binder.clearCallingIdentity();
try {
mService.grantInputChannel(mUid, mPid, displayId, surface, window, hostInputToken,
- flags, outInputChannel);
+ flags, mCanAddInternalSystemWindow ? type : 0, outInputChannel);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 0f5cafe..1a2672b 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -297,6 +297,13 @@
Slog.w(TAG_WM, "Failed to take screenshot. No main window for " + task);
return false;
}
+ if (activity.hasFixedRotationTransform()) {
+ if (DEBUG_SCREENSHOT) {
+ Slog.i(TAG_WM, "Skip taking screenshot. App has fixed rotation " + activity);
+ }
+ // The activity is in a temporal state that it has different rotation than the task.
+ return false;
+ }
builder.setIsRealSnapshot(true);
builder.setId(System.currentTimeMillis());
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 24cd7d1..3925570 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -195,6 +195,16 @@
+ activity);
return null;
}
+ if (topFullscreenActivity.getWindowConfiguration().getRotation()
+ != snapshot.getRotation()) {
+ // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
+ // that the activity will be updated to the same rotation as the snapshot. Since
+ // the transition is not started yet, fixed rotation transform needs to be applied
+ // earlier to make the snapshot show in a rotated container.
+ activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
+ topFullscreenActivity, false /* checkOpening */);
+ }
+
sysUiVis = topFullscreenOpaqueWindow.getSystemUiVisibility();
WindowManager.LayoutParams attrs = topFullscreenOpaqueWindow.mAttrs;
windowFlags = attrs.flags;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4c1d6f3..86d83c2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8027,14 +8027,15 @@
* views.
*/
void grantInputChannel(int callingUid, int callingPid, int displayId, SurfaceControl surface,
- IWindow window, IBinder hostInputToken, int flags, InputChannel outInputChannel) {
+ IWindow window, IBinder hostInputToken, int flags, int type,
+ InputChannel outInputChannel) {
final InputApplicationHandle applicationHandle;
final String name;
final InputChannel clientChannel;
synchronized (mGlobalLock) {
EmbeddedWindowController.EmbeddedWindow win =
new EmbeddedWindowController.EmbeddedWindow(this, window,
- mInputToWindowMap.get(hostInputToken), callingUid, callingPid);
+ mInputToWindowMap.get(hostInputToken), callingUid, callingPid, type);
clientChannel = win.openInputChannel();
mEmbeddedWindowController.add(clientChannel.getToken(), win);
applicationHandle = win.getApplicationHandle();
@@ -8042,7 +8043,7 @@
}
updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface,
- name, applicationHandle, flags, null /* region */);
+ name, applicationHandle, flags, type, null /* region */);
clientChannel.transferTo(outInputChannel);
clientChannel.dispose();
@@ -8050,7 +8051,7 @@
private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid,
int displayId, SurfaceControl surface, String name,
- InputApplicationHandle applicationHandle, int flags, Region region) {
+ InputApplicationHandle applicationHandle, int flags, int type, Region region) {
InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId);
h.token = channelToken;
h.name = name;
@@ -8058,7 +8059,7 @@
final int sanitizedFlags = flags & (LayoutParams.FLAG_NOT_TOUCHABLE
| LayoutParams.FLAG_SLIPPERY);
h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags;
- h.layoutParamsType = 0;
+ h.layoutParamsType = type;
h.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
h.canReceiveKeys = false;
h.hasFocus = false;
@@ -8082,6 +8083,7 @@
t.setInputWindowInfo(surface, h);
t.apply();
t.close();
+ surface.release();
}
/**
@@ -8105,7 +8107,7 @@
}
updateInputChannel(channelToken, win.mOwnerUid, win.mOwnerPid, displayId, surface, name,
- applicationHandle, flags, region);
+ applicationHandle, flags, win.mWindowType, region);
}
/** Return whether layer tracing is enabled */
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index c4cb4b5..707a789 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -138,6 +138,13 @@
Slog.e(TAG, "Attempt to operate on detached container: " + wc);
continue;
}
+ // Make sure we add to the syncSet before performing
+ // operations so we don't end up splitting effects between the WM
+ // pending transaction and the BLASTSync transaction.
+ if (syncId >= 0) {
+ mBLASTSyncEngine.addToSyncSet(syncId, wc);
+ }
+
int containerEffect = applyWindowContainerChange(wc, entry.getValue());
effects |= containerEffect;
@@ -146,9 +153,6 @@
&& (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
haveConfigChanges.add(wc);
}
- if (syncId >= 0) {
- mBLASTSyncEngine.addToSyncSet(syncId, wc);
- }
}
// Hierarchy changes
final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e925ce5..a948ece 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2191,9 +2191,9 @@
if (wasVisible) {
final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;
-
+ final int flags = startingWindow ? 0 /* self */ : PARENTS;
// Try starting an animation.
- if (mWinAnimator.applyAnimationLocked(transit, false)) {
+ if (mWinAnimator.applyAnimationLocked(transit, false, flags)) {
mAnimatingExit = true;
// mAnimatingExit affects canAffectSystemUiFlags(). Run layout such that
@@ -2205,7 +2205,9 @@
mWmService.mAccessibilityController.onWindowTransitionLocked(this, transit);
}
}
- final boolean isAnimating = isAnimating(TRANSITION | PARENTS)
+ final boolean isAnimating = startingWindow
+ ? isAnimating(0)
+ : isAnimating(TRANSITION | PARENTS)
&& (mActivityRecord == null || !mActivityRecord.isWaitingForTransitionStart());
final boolean lastWindowIsStartingWindow = startingWindow && mActivityRecord != null
&& mActivityRecord.isLastWindow(this);
@@ -2227,6 +2229,9 @@
}
}
+ if (startingWindow && mActivityRecord != null) {
+ mActivityRecord.startingDisplayed = false;
+ }
removeImmediately();
// Removing a visible window will effect the computed orientation
// So just update orientation if needed.
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index c570cf1..e70f3e4 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1400,9 +1400,25 @@
* the switch statement below.
* @param isEntrance The animation type the last time this was called. Used to keep from
* loading the same animation twice.
- * @return true if an animation has been loaded.
+ * @return {@code true} if an animation has been loaded, includes the parents.
+ *
*/
boolean applyAnimationLocked(int transit, boolean isEntrance) {
+ return applyAnimationLocked(transit, isEntrance, PARENTS);
+ }
+
+ /**
+ * Choose the correct animation and set it to the passed WindowState.
+ * @param transit If AppTransition.TRANSIT_PREVIEW_DONE and the app window has been drawn
+ * then the animation will be app_starting_exit. Any other value loads the animation from
+ * the switch statement below.
+ * @param isEntrance The animation type the last time this was called. Used to keep from
+ * loading the same animation twice.
+ * @param flags The combination of bitmask flags to specify targets and condition for
+ * checking animating status. See {@link WindowContainer.AnimationFlags}.
+ * @return {@code true} if an animation has been loaded.
+ */
+ boolean applyAnimationLocked(int transit, boolean isEntrance, int flags) {
if (mWin.isAnimating() && mAnimationIsEntrance == isEntrance) {
// If we are trying to apply an animation, but already running
// an animation of the same type, then just leave that one alone.
@@ -1472,7 +1488,7 @@
mWin.getDisplayContent().adjustForImeIfNeeded();
}
- return mWin.isAnimating(PARENTS);
+ return mWin.isAnimating(flags);
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 48e22f6..e410220 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -63,6 +63,7 @@
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -107,6 +108,10 @@
private static final int UID_1 = 10000;
private static final String PACKAGE_EXEMPTED_1 = "com.android.exempted";
private static final int UID_EXEMPTED_1 = 10001;
+ private static final String PACKAGE_SYSTEM_HEADFULL = "com.example.system.headfull";
+ private static final int UID_SYSTEM_HEADFULL = 10002;
+ private static final String PACKAGE_SYSTEM_HEADLESS = "com.example.system.headless";
+ private static final int UID_SYSTEM_HEADLESS = 10003;
private static final int USER_ID = 0;
private static final int USER_ID2 = 10;
private static final UserHandle USER_HANDLE_USER2 = new UserHandle(USER_ID2);
@@ -305,18 +310,33 @@
pie.packageName = PACKAGE_EXEMPTED_1;
packages.add(pie);
+ PackageInfo pis = new PackageInfo();
+ pis.activities = new ActivityInfo[]{mock(ActivityInfo.class)};
+ pis.applicationInfo = new ApplicationInfo();
+ pis.applicationInfo.uid = UID_SYSTEM_HEADFULL;
+ pis.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+ pis.packageName = PACKAGE_SYSTEM_HEADFULL;
+ packages.add(pis);
+
+ PackageInfo pish = new PackageInfo();
+ pish.applicationInfo = new ApplicationInfo();
+ pish.applicationInfo.uid = UID_SYSTEM_HEADLESS;
+ pish.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+ pish.packageName = PACKAGE_SYSTEM_HEADLESS;
+ packages.add(pish);
+
doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(), anyInt());
try {
- doReturn(UID_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_1), anyInt());
- doReturn(UID_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_1), anyInt(), anyInt());
- doReturn(UID_EXEMPTED_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_EXEMPTED_1),
- anyInt());
- doReturn(UID_EXEMPTED_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_EXEMPTED_1),
- anyInt(), anyInt());
- doReturn(pi.applicationInfo).when(mockPm).getApplicationInfo(eq(pi.packageName),
- anyInt());
- doReturn(pie.applicationInfo).when(mockPm).getApplicationInfo(eq(pie.packageName),
- anyInt());
+ for (int i = 0; i < packages.size(); ++i) {
+ PackageInfo pkg = packages.get(i);
+
+ doReturn(pkg.applicationInfo.uid).when(mockPm)
+ .getPackageUidAsUser(eq(pkg.packageName), anyInt());
+ doReturn(pkg.applicationInfo.uid).when(mockPm)
+ .getPackageUidAsUser(eq(pkg.packageName), anyInt(), anyInt());
+ doReturn(pkg.applicationInfo).when(mockPm)
+ .getApplicationInfo(eq(pkg.packageName), anyInt());
+ }
} catch (PackageManager.NameNotFoundException nnfe) {}
}
@@ -514,7 +534,11 @@
}
private void assertBucket(int bucket) {
- assertEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
+ assertBucket(bucket, PACKAGE_1);
+ }
+
+ private void assertBucket(int bucket, String pkg) {
+ assertEquals(bucket, getStandbyBucket(mController, pkg));
}
private void assertNotBucket(int bucket) {
@@ -1462,6 +1486,32 @@
assertBucket(STANDBY_BUCKET_RESTRICTED);
}
+ @Test
+ public void testSystemHeadlessAppElevated() {
+ reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
+ reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime,
+ PACKAGE_SYSTEM_HEADFULL);
+ reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime,
+ PACKAGE_SYSTEM_HEADLESS);
+ mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
+
+
+ mController.setAppStandbyBucket(PACKAGE_SYSTEM_HEADFULL, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_MAIN_TIMEOUT);
+ assertBucket(STANDBY_BUCKET_RARE, PACKAGE_SYSTEM_HEADFULL);
+
+ // Make sure headless system apps don't get lowered.
+ mController.setAppStandbyBucket(PACKAGE_SYSTEM_HEADLESS, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_MAIN_TIMEOUT);
+ assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_SYSTEM_HEADLESS);
+
+ // Package 1 doesn't have activities and is headless, but is not a system app, so it can
+ // be lowered.
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_MAIN_TIMEOUT);
+ assertBucket(STANDBY_BUCKET_RARE, PACKAGE_1);
+ }
+
private String getAdminAppsStr(int userId) {
return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8cfe96f..4da5adf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -35,6 +35,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
@@ -69,6 +70,7 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
+import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.app.servertransaction.ActivityConfigurationChangeItem;
@@ -82,14 +84,18 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.os.PersistableBundle;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.MergedConfiguration;
import android.util.MutableBoolean;
import android.view.DisplayInfo;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner.Stub;
+import android.view.IWindowSession;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import androidx.test.filters.MediumTest;
@@ -488,6 +494,16 @@
}
@Test
+ public void testShouldMakeActive_nonTopVisible() {
+ ActivityRecord finishingActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ finishingActivity.finishing = true;
+ ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
+
+ assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
+ }
+
+ @Test
public void testShouldResume_stackVisibility() {
mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
spyOn(mStack);
@@ -1394,6 +1410,10 @@
assertTrue(displayRotation.isRotatingSeamlessly());
+ // The launching rotated app should not be cleared when waiting for remote rotation.
+ display.continueUpdateOrientationForDiffOrienLaunchingApp();
+ assertNotNull(display.mFixedRotationLaunchingApp);
+
// Simulate the rotation has been updated to previous one, e.g. sensor updates before the
// remote rotation is completed.
doReturn(originalRotation).when(displayRotation).rotationForOrientation(
@@ -1426,6 +1446,73 @@
}
@Test
+ public void testIsSnapshotCompatible() {
+ mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
+ final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
+ .setRotation(mActivity.getWindowConfiguration().getRotation())
+ .build();
+
+ assertTrue(mActivity.isSnapshotCompatible(snapshot));
+
+ setRotatedScreenOrientationSilently(mActivity);
+
+ assertFalse(mActivity.isSnapshotCompatible(snapshot));
+ }
+
+ @Test
+ public void testFixedRotationSnapshotStartingWindow() {
+ mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
+ // TaskSnapshotSurface requires a fullscreen opaque window.
+ final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+ WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
+ params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT;
+ final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
+ mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
+ mActivity.addWindow(w);
+
+ // Assume the activity is launching in different rotation, and there was an available
+ // snapshot accepted by {@link Activity#isSnapshotCompatible}.
+ final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
+ .setRotation((mActivity.getWindowConfiguration().getRotation() + 1) % 4)
+ .build();
+ setRotatedScreenOrientationSilently(mActivity);
+
+ final IWindowSession session = WindowManagerGlobal.getWindowSession();
+ spyOn(session);
+ try {
+ // Return error to skip unnecessary operation.
+ doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
+ any() /* window */, anyInt() /* seq */, any() /* attrs */,
+ anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* outFrame */,
+ any() /* outContentInsets */, any() /* outStableInsets */,
+ any() /* outDisplayCutout */, any() /* outInputChannel */,
+ any() /* outInsetsState */, any() /* outActiveControls */);
+ TaskSnapshotSurface.create(mService.mWindowManager, mActivity, snapshot);
+ } catch (RemoteException ignored) {
+ } finally {
+ reset(session);
+ }
+
+ // Because the rotation of snapshot and the corresponding top activity are different, fixed
+ // rotation should be applied when creating snapshot surface if the display rotation may be
+ // changed according to the activity orientation.
+ assertTrue(mActivity.hasFixedRotationTransform());
+ assertEquals(mActivity, mActivity.mDisplayContent.mFixedRotationLaunchingApp);
+ }
+
+ /**
+ * Sets orientation without notifying the parent to simulate that the display has not applied
+ * the requested orientation yet.
+ */
+ private static void setRotatedScreenOrientationSilently(ActivityRecord r) {
+ final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT
+ ? SCREEN_ORIENTATION_LANDSCAPE
+ : SCREEN_ORIENTATION_PORTRAIT;
+ doReturn(false).when(r).onDescendantOrientationChanged(any(), any());
+ r.setOrientation(rotatedOrentation);
+ }
+
+ @Test
public void testActivityOnDifferentDisplayUpdatesProcessOverride() {
final ActivityRecord secondaryDisplayActivity =
createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 02d1f9b..edc9756 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -49,7 +49,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -57,10 +56,10 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -100,6 +99,7 @@
@Presubmit
@RunWith(WindowTestRunner.class)
public class ActivityStarterTests extends ActivityTestsBase {
+ private ActivityStarter mStarter;
private ActivityStartController mController;
private ActivityMetricsLogger mActivityMetricsLogger;
private PackageManagerInternal mMockPackageManager;
@@ -127,6 +127,8 @@
mController = mock(ActivityStartController.class);
mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
clearInvocations(mActivityMetricsLogger);
+ mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor,
+ mock(ActivityStartInterceptor.class));
}
@Test
@@ -179,7 +181,6 @@
* {@link ActivityStarter#execute} based on these preconditions and ensures the result matches
* the expected. It is important to note that the method also checks side effects of the start,
* such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios.
- *
* @param preconditions A bitmask representing the preconditions for the launch
* @param launchFlags The launch flags to be provided by the launch {@link Intent}.
* @param expectedResult The expected result from the launch.
@@ -201,7 +202,7 @@
final WindowProcessController wpc =
containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
? null : new WindowProcessController(service, ai, null, 0, -1, null, listener);
- doReturn(wpc).when(service).getProcessController(any());
+ doReturn(wpc).when(service).getProcessController(anyObject());
final Intent intent = new Intent();
intent.setFlags(launchFlags);
@@ -1033,46 +1034,4 @@
verify(recentTasks, times(1)).add(any());
}
-
- @Test
- public void testStartActivityInner_allSplitScreenPrimaryActivitiesVisible() {
- // Given
- final ActivityStarter starter = prepareStarter(0, false);
-
- starter.setReason("testAllSplitScreenPrimaryActivitiesAreResumed");
-
- final ActivityRecord targetRecord = new ActivityBuilder(mService).build();
- targetRecord.setFocusable(false);
- targetRecord.setVisibility(false);
- final ActivityRecord sourceRecord = new ActivityBuilder(mService).build();
-
- final ActivityStack stack = spy(
- mRootWindowContainer.getDefaultTaskDisplayArea()
- .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
- /* onTop */true));
-
- stack.addChild(targetRecord);
-
- doReturn(stack).when(mRootWindowContainer)
- .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
-
- starter.mStartActivity = new ActivityBuilder(mService).build();
-
- // When
- starter.startActivityInner(
- /* r */targetRecord,
- /* sourceRecord */ sourceRecord,
- /* voiceSession */null,
- /* voiceInteractor */ null,
- /* startFlags */ 0,
- /* doResume */true,
- /* options */null,
- /* inTask */null,
- /* restrictedBgActivity */false);
-
- // Then
- verify(stack).ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
- verify(targetRecord).makeVisibleIfNeeded(null, true);
- assertTrue(targetRecord.mVisibleRequested);
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 9263d8a..8f18f64 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -307,7 +307,7 @@
public void testCreateRemoveStartingWindow() {
mActivity.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
assertHasStartingWindow(mActivity);
mActivity.removeStartingWindow();
@@ -322,7 +322,7 @@
for (int i = 0; i < 1000; i++) {
appToken.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
appToken.removeStartingWindow();
waitUntilHandlersIdle();
assertNoStartingWindow(appToken);
@@ -335,11 +335,11 @@
final ActivityRecord activity2 = createIsolatedTestActivityRecord();
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
- true, true, false, true, false, false);
+ true, true, false, true, false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
@@ -355,11 +355,11 @@
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0,
activity1.appToken.asBinder(), true, true, false,
- true, false, false);
+ true, false);
});
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
@@ -371,11 +371,11 @@
final ActivityRecord activity2 = createIsolatedTestActivityRecord();
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
- true, true, false, true, false, false);
+ true, true, false, true, false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
@@ -413,7 +413,7 @@
// Add a starting window.
activityTop.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
- false, false);
+ false);
waitUntilHandlersIdle();
// Make the top one invisible, and try transferring the starting window from the top to the
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 20d9aff..f985a14 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -192,10 +192,18 @@
final ActivityManager.TaskSnapshot.Builder builder =
new ActivityManager.TaskSnapshot.Builder();
- mWm.mTaskSnapshotController.prepareTaskSnapshot(mAppWindow.mActivityRecord.getTask(),
- PixelFormat.UNKNOWN, builder);
+ boolean success = mWm.mTaskSnapshotController.prepareTaskSnapshot(
+ mAppWindow.mActivityRecord.getTask(), PixelFormat.UNKNOWN, builder);
+ assertTrue(success);
// The pixel format should be selected automatically.
assertNotEquals(PixelFormat.UNKNOWN, builder.getPixelFormat());
+
+ // Snapshot should not be taken while the rotation of activity and task are different.
+ doReturn(true).when(mAppWindow.mActivityRecord).hasFixedRotationTransform();
+ success = mWm.mTaskSnapshotController.prepareTaskSnapshot(
+ mAppWindow.mActivityRecord.getTask(), PixelFormat.UNKNOWN, builder);
+
+ assertFalse(success);
}
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e85dfbe..4246aef 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10415,7 +10415,7 @@
* <p>To recognize a carrier (including MVNO) as a first-class identity, Android assigns each
* carrier with a canonical integer a.k.a. carrier id. The carrier ID is an Android
* platform-wide identifier for a carrier. AOSP maintains carrier ID assignments in
- * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+ * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
*
* <p>Apps which have carrier-specific configurations or business logic can use the carrier id
* as an Android platform-wide identifier for carriers.
@@ -10477,7 +10477,7 @@
*
* <p>For carriers without fine-grained specific carrier ids, return {@link #getSimCarrierId()}
* <p>Specific carrier ids are defined in the same way as carrier id
- * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+ * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
* except each with a "parent" id linking to its top-level carrier id.
*
* @return Returns fine-grained carrier id of the current subscription.
@@ -10526,7 +10526,7 @@
* This is used for fallback when configurations/logic for exact carrier id
* {@link #getSimCarrierId()} are not found.
*
- * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+ * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
* can be updated out-of-band, its possible a MVNO (Mobile Virtual Network Operator) carrier
* was not fully recognized and assigned to its MNO (Mobile Network Operator) carrier id
* by default. After carrier id table update, a new carrier id was assigned. If apps don't
@@ -10553,7 +10553,7 @@
* used for fallback when configurations/logic for exact carrier id {@link #getSimCarrierId()}
* are not found.
*
- * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+ * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
* can be updated out-of-band, its possible a MVNO (Mobile Virtual Network Operator) carrier
* was not fully recognized and assigned to its MNO (Mobile Network Operator) carrier id
* by default. After carrier id table update, a new carrier id was assigned. If apps don't