Merge "Stop supporting null IME token in IMM#switchToLastInputMethod()"
diff --git a/api/current.txt b/api/current.txt
index 8919257..784f454 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6664,7 +6664,7 @@
method public void setDelegatedScopes(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setEndUserSessionMessage(android.content.ComponentName, java.lang.CharSequence);
- method public void setGlobalPrivateDns(android.content.ComponentName, int, java.lang.String);
+ method public int setGlobalPrivateDns(android.content.ComponentName, int, java.lang.String);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setKeepUninstalledPackages(android.content.ComponentName, java.util.List<java.lang.String>);
method public boolean setKeyPairCertificate(android.content.ComponentName, java.lang.String, java.util.List<java.security.cert.Certificate>, boolean);
@@ -6845,6 +6845,9 @@
field public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; // 0x2
field public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; // 0x3
field public static final int PRIVATE_DNS_MODE_UNKNOWN = 0; // 0x0
+ field public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 2; // 0x2
+ field public static final int PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING = 1; // 0x1
+ field public static final int PRIVATE_DNS_SET_SUCCESS = 0; // 0x0
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
diff --git a/api/system-current.txt b/api/system-current.txt
index 9873c37..55cfa60 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1036,6 +1036,10 @@
package android.content {
+ public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
+ method public void setDetectNotResponding(long);
+ }
+
public abstract class Context {
method public boolean bindServiceAsUser(android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
method public abstract android.content.Context createCredentialProtectedStorageContext();
@@ -4533,6 +4537,11 @@
field public static final int FLAG_REMOVABLE_USB = 524288; // 0x80000
}
+ public final class MediaStore {
+ method public static void deleteContributedMedia(android.content.Context, java.lang.String);
+ method public static long getContributedMediaSize(android.content.Context, java.lang.String);
+ }
+
public abstract class SearchIndexableData {
ctor public SearchIndexableData();
ctor public SearchIndexableData(android.content.Context);
diff --git a/api/test-current.txt b/api/test-current.txt
index b6a42ec..91e8ec6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -299,6 +299,10 @@
package android.content {
+ public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
+ method public void setDetectNotResponding(long);
+ }
+
public abstract class ContentResolver implements android.content.ContentInterface {
method public static java.lang.String[] getSyncAdapterPackagesForAuthorityAsUser(java.lang.String, int);
}
@@ -983,6 +987,11 @@
field public static final android.net.Uri CORP_CONTENT_URI;
}
+ public final class MediaStore {
+ method public static void deleteContributedMedia(android.content.Context, java.lang.String);
+ method public static long getContributedMediaSize(android.content.Context, java.lang.String);
+ }
+
public final class Settings {
field public static final java.lang.String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
}
diff --git a/cmds/device_config/Android.mk b/cmds/device_config/Android.mk
new file mode 100644
index 0000000..4041e01
--- /dev/null
+++ b/cmds/device_config/Android.mk
@@ -0,0 +1,10 @@
+# Copyright 2018 The Android Open Source Project
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := device_config
+LOCAL_SRC_FILES := device_config
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
diff --git a/cmds/device_config/device_config b/cmds/device_config/device_config
new file mode 100755
index 0000000..a949bd5
--- /dev/null
+++ b/cmds/device_config/device_config
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+cmd device_config "$@"
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e826250..8e54961 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -49,6 +49,8 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
+import android.net.NetworkUtils;
+import android.net.PrivateDnsConnectivityChecker;
import android.net.ProxyInfo;
import android.net.Uri;
import android.os.Binder;
@@ -79,6 +81,7 @@
import android.service.restrictions.RestrictionsReceiver;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -2032,6 +2035,35 @@
public @interface InstallUpdateCallbackErrorConstants {}
/**
+ * The selected mode has been set successfully. If the mode is
+ * {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} then it implies the supplied host is valid
+ * and reachable.
+ */
+ public static final int PRIVATE_DNS_SET_SUCCESS = 0;
+
+ /**
+ * If the {@code privateDnsHost} provided was of a valid hostname but that host was found
+ * to not support DNS-over-TLS.
+ */
+ public static final int PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING = 1;
+
+ /**
+ * General failure to set the Private DNS mode, not due to one of the reasons listed above.
+ */
+ public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 2;
+
+ /**
+ * @hide
+ */
+ @IntDef(prefix = {"PRIVATE_DNS_SET_"}, value = {
+ PRIVATE_DNS_SET_SUCCESS,
+ PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING,
+ PRIVATE_DNS_SET_ERROR_FAILURE_SETTING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SetPrivateDnsModeResultConstants {}
+
+ /**
* Return true if the given administrator component is currently active (enabled) in the system.
*
* @param admin The administrator component to check for.
@@ -9897,6 +9929,16 @@
* Sets the global Private DNS mode and host to be used.
* May only be called by the device owner.
*
+ * <p>Note that in case a Private DNS resolver is specified, the method is blocking as it
+ * will perform a connectivity check to the resolver, to ensure it is valid. Because of that,
+ * the method should not be called on any thread that relates to user interaction, such as the
+ * UI thread.
+ *
+ * <p>In case a VPN is used in conjunction with Private DNS resolver, the Private DNS resolver
+ * must be reachable both from within and outside the VPN. Otherwise, the device may lose
+ * the ability to resolve hostnames as system traffic to the resolver may not go through the
+ * VPN.
+ *
* @param admin which {@link DeviceAdminReceiver} this request is associated with.
* @param mode Which mode to set - either {@code PRIVATE_DNS_MODE_OPPORTUNISTIC} or
* {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME}.
@@ -9906,6 +9948,9 @@
* @param privateDnsHost The hostname of a server that implements DNS over TLS (RFC7858), if
* {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} was specified as the mode,
* null otherwise.
+ *
+ * @return One of the values in {@link SetPrivateDnsModeResultConstants}.
+ *
* @throws IllegalArgumentException in the following cases: if a {@code privateDnsHost} was
* provided but the mode was not {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME}, if the mode
* specified was {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} but {@code privateDnsHost} does
@@ -9913,15 +9958,23 @@
*
* @throws SecurityException if the caller is not the device owner.
*/
- public void setGlobalPrivateDns(@NonNull ComponentName admin,
+ public int setGlobalPrivateDns(@NonNull ComponentName admin,
@PrivateDnsMode int mode, @Nullable String privateDnsHost) {
throwIfParentInstance("setGlobalPrivateDns");
+
if (mService == null) {
- return;
+ return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
+ }
+
+ if (mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME && !TextUtils.isEmpty(privateDnsHost)
+ && NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
+ if (!PrivateDnsConnectivityChecker.canConnectToPrivateDnsServer(privateDnsHost)) {
+ return PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING;
+ }
}
try {
- mService.setGlobalPrivateDns(admin, mode, privateDnsHost);
+ return mService.setGlobalPrivateDns(admin, mode, privateDnsHost);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index fcf74ee..1148685 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -415,7 +415,7 @@
boolean isMeteredDataDisabledPackageForUser(in ComponentName admin, String packageName, int userId);
- void setGlobalPrivateDns(in ComponentName admin, int mode, in String privateDnsHost);
+ int setGlobalPrivateDns(in ComponentName admin, int mode, in String privateDnsHost);
int getGlobalPrivateDnsMode(in ComponentName admin);
String getGlobalPrivateDnsHost(in ComponentName admin);
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index cd7a1a1..0b5bdb5 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -16,8 +16,12 @@
package android.content;
+import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.content.res.AssetFileDescriptor;
import android.database.CrossProcessCursorWrapper;
@@ -106,8 +110,20 @@
mCloseGuard.open("close");
}
- /** {@hide} */
- public void setDetectNotResponding(long timeoutMillis) {
+ /**
+ * Configure this client to automatically detect and kill the remote
+ * provider when an "application not responding" event is detected.
+ *
+ * @param timeoutMillis the duration for which a pending call is allowed
+ * block before the remote provider is considered to be
+ * unresponsive. Set to {@code 0} to allow pending calls to block
+ * indefinitely with no action taken.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.REMOVE_TASKS)
+ public void setDetectNotResponding(@DurationMillisLong long timeoutMillis) {
synchronized (ContentProviderClient.class) {
mAnrTimeout = timeoutMillis;
diff --git a/core/java/android/net/PrivateDnsConnectivityChecker.java b/core/java/android/net/PrivateDnsConnectivityChecker.java
new file mode 100644
index 0000000..cfd458c
--- /dev/null
+++ b/core/java/android/net/PrivateDnsConnectivityChecker.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Class for testing connectivity to DNS-over-TLS servers.
+ * {@hide}
+ */
+public class PrivateDnsConnectivityChecker {
+ private static final String TAG = "NetworkUtils";
+
+ private static final int PRIVATE_DNS_PORT = 853;
+ private static final int CONNECTION_TIMEOUT_MS = 5000;
+
+ private PrivateDnsConnectivityChecker() { }
+
+ /**
+ * checks that a provided host can perform a TLS handshake on port 853.
+ * @param hostname host to connect to.
+ */
+ public static boolean canConnectToPrivateDnsServer(@NonNull String hostname) {
+ final SocketFactory factory = SSLSocketFactory.getDefault();
+ TrafficStats.setThreadStatsTag(TrafficStats.TAG_SYSTEM_APP);
+
+ try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
+ socket.setSoTimeout(CONNECTION_TIMEOUT_MS);
+ socket.connect(new InetSocketAddress(hostname, PRIVATE_DNS_PORT));
+ if (!socket.isConnected()) {
+ Log.w(TAG, String.format("Connection to %s failed.", hostname));
+ return false;
+ }
+ socket.startHandshake();
+ Log.w(TAG, String.format("TLS handshake to %s succeeded.", hostname));
+ return true;
+ } catch (IOException e) {
+ Log.w(TAG, String.format("TLS handshake to %s failed.", hostname), e);
+ return false;
+ }
+ }
+}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 8cafbde..7abe913 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -16,14 +16,13 @@
package android.os;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.opengl.EGL14;
-import android.os.Build;
-import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
@@ -37,6 +36,11 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/** @hide */
public class GraphicsEnvironment {
@@ -67,7 +71,7 @@
*/
public void setup(Context context, Bundle coreSettings) {
setupGpuLayers(context, coreSettings);
- setupAngle(context, coreSettings);
+ setupAngle(context, context.getPackageName());
chooseDriver(context, coreSettings);
}
@@ -192,24 +196,101 @@
setLayerPaths(mClassLoader, layerPaths);
}
+ enum OpenGlDriverChoice {
+ DEFAULT,
+ NATIVE,
+ ANGLE
+ }
+
+ private static final Map<OpenGlDriverChoice, String> sDriverMap = buildMap();
+ private static Map<OpenGlDriverChoice, String> buildMap() {
+ Map<OpenGlDriverChoice, String> map = new HashMap<>();
+ map.put(OpenGlDriverChoice.DEFAULT, "default");
+ map.put(OpenGlDriverChoice.ANGLE, "angle");
+ map.put(OpenGlDriverChoice.NATIVE, "native");
+
+ return map;
+ }
+
+
+ private static List<String> getGlobalSettingsString(Context context, String globalSetting) {
+ List<String> valueList = null;
+ ContentResolver contentResolver = context.getContentResolver();
+ String settingsValue = Settings.Global.getString(contentResolver, globalSetting);
+
+ if (settingsValue != null) {
+ valueList = new ArrayList<>(Arrays.asList(settingsValue.split(",")));
+ } else {
+ valueList = new ArrayList<>();
+ }
+
+ return valueList;
+ }
+
+ private static int getGlobalSettingsPkgIndex(String pkgName,
+ List<String> globalSettingsDriverPkgs) {
+ for (int pkgIndex = 0; pkgIndex < globalSettingsDriverPkgs.size(); pkgIndex++) {
+ if (globalSettingsDriverPkgs.get(pkgIndex).equals(pkgName)) {
+ return pkgIndex;
+ }
+ }
+
+ return -1;
+ }
+
+ private static String getDriverForPkg(Context context, String packageName) {
+ try {
+ ContentResolver contentResolver = context.getContentResolver();
+ int allUseAngle = Settings.Global.getInt(contentResolver,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
+ if (allUseAngle == 1) {
+ return sDriverMap.get(OpenGlDriverChoice.ANGLE);
+ }
+ } catch (Settings.SettingNotFoundException e) {
+ // Do nothing and move on
+ }
+
+ List<String> globalSettingsDriverPkgs =
+ getGlobalSettingsString(context,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
+ List<String> globalSettingsDriverValues =
+ getGlobalSettingsString(context,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
+
+ // Make sure we have a good package name
+ if ((packageName == null) || (packageName.isEmpty())) {
+ return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
+ }
+ // Make sure we have good settings to use
+ if (globalSettingsDriverPkgs.isEmpty() || globalSettingsDriverValues.isEmpty()
+ || (globalSettingsDriverPkgs.size() != globalSettingsDriverValues.size())) {
+ Log.w(TAG,
+ "Global.Settings values are invalid: "
+ + "globalSettingsDriverPkgs.size = "
+ + globalSettingsDriverPkgs.size() + ", "
+ + "globalSettingsDriverValues.size = "
+ + globalSettingsDriverValues.size());
+ return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
+ }
+
+ int pkgIndex = getGlobalSettingsPkgIndex(packageName, globalSettingsDriverPkgs);
+
+ if (pkgIndex < 0) {
+ return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
+ }
+
+ return globalSettingsDriverValues.get(pkgIndex);
+ }
+
/**
* Pass ANGLE details down to trigger enable logic
*/
- private static void setupAngle(Context context, Bundle coreSettings) {
+ private void setupAngle(Context context, String packageName) {
+ String devOptIn = getDriverForPkg(context, packageName);
- String angleEnabledApp =
- coreSettings.getString(Settings.Global.ANGLE_ENABLED_APP);
-
- String packageName = context.getPackageName();
-
- boolean devOptIn = false;
- if ((angleEnabledApp != null && packageName != null)
- && (!angleEnabledApp.isEmpty() && !packageName.isEmpty())
- && angleEnabledApp.equals(packageName)) {
-
- Log.i(TAG, packageName + " opted in for ANGLE via Developer Setting");
-
- devOptIn = true;
+ if (DEBUG) {
+ Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
+ + "set to: '" + devOptIn + "'");
}
ApplicationInfo angleInfo;
@@ -303,8 +384,7 @@
// Further opt-in logic is handled in native, so pass relevant info down
// TODO: Move the ANGLE selection logic earlier so we don't need to keep these
// file descriptors open.
- setAngleInfo(paths, packageName, devOptIn,
- rulesFd, rulesOffset, rulesLength);
+ setAngleInfo(paths, packageName, devOptIn, rulesFd, rulesOffset, rulesLength);
}
/**
@@ -452,6 +532,6 @@
private static native void setDebugLayersGLES(String layers);
private static native void setDriverPath(String path);
private static native void setAngleInfo(String path, String appPackage,
- boolean devOptIn, FileDescriptor rulesFd,
+ String devOptIn, FileDescriptor rulesFd,
long rulesOffset, long rulesLength);
}
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 92fe028..865b8f8 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -717,7 +717,7 @@
* <p>This uri will return an empty cursor if the calling user is not a parent profile
* of a work profile, or cross profile calendar is disabled in Settings, or this uri is
* queried from a package that is not whitelisted by profile owner of the work profile via
- * {@link DevicePolicyManager.addCrossProfileCalendarPackage(ComponentName, String)}.
+ * {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}.
*
* @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName)
* @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED
@@ -1708,7 +1708,7 @@
* <p>This uri will return an empty cursor if the calling user is not a parent profile
* of a work profile, or cross profile calendar is disabled in Settings, or this uri is
* queried from a package that is not whitelisted by profile owner of the work profile via
- * {@link DevicePolicyManager.addCrossProfileCalendarPackage(ComponentName, String)}.
+ * {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}.
*
* @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName)
* @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED
@@ -1919,7 +1919,7 @@
* of a work profile, or cross profile calendar for the work profile is disabled in
* Settings, or this uri is queried from a package that is not whitelisted by
* profile owner of the work profile via
- * {@link DevicePolicyManager.addCrossProfileCalendarPackage(ComponentName, String)}.
+ * {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}.
*
* @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName)
* @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 0299e41..1451165 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -16,11 +16,15 @@
package android.provider;
+import android.annotation.BytesLong;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.Activity;
import android.app.AppGlobals;
@@ -102,6 +106,11 @@
/** {@hide} */
public static final String GET_MEDIA_URI_CALL = "get_media_uri";
+ /** {@hide} */
+ public static final String GET_CONTRIBUTED_MEDIA_CALL = "get_contributed_media";
+ /** {@hide} */
+ public static final String DELETE_CONTRIBUTED_MEDIA_CALL = "delete_contributed_media";
+
/**
* This is for internal use by the media scanner only.
* Name of the (optional) Uri parameter that determines whether to skip deleting
@@ -2865,4 +2874,47 @@
throw e.rethrowAsRuntimeException();
}
}
+
+ /**
+ * Calculate size of media contributed by given package under the calling
+ * user. The meaning of "contributed" means it won't automatically be
+ * deleted when the app is uninstalled.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA)
+ public static @BytesLong long getContributedMediaSize(Context context, String packageName) {
+ try (ContentProviderClient client = context.getContentResolver()
+ .acquireContentProviderClient(AUTHORITY)) {
+ final Bundle in = new Bundle();
+ in.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
+ final Bundle out = client.call(GET_CONTRIBUTED_MEDIA_CALL, null, in);
+ return out.getLong(Intent.EXTRA_INDEX);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Delete all media contributed by given package under the calling user. The
+ * meaning of "contributed" means it won't automatically be deleted when the
+ * app is uninstalled.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA)
+ public static void deleteContributedMedia(Context context, String packageName) {
+ try (ContentProviderClient client = context.getContentResolver()
+ .acquireContentProviderClient(AUTHORITY)) {
+ final Bundle in = new Bundle();
+ in.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
+ client.call(DELETE_CONTRIBUTED_MEDIA_CALL, null, in);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 98a1701..3437e1d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11878,10 +11878,26 @@
public static final String GPU_DEBUG_APP = "gpu_debug_app";
/**
- * App should try to use ANGLE
+ * Force all PKGs to use ANGLE, regardless of any other settings
+ * The value is a boolean (1 or 0).
* @hide
*/
- public static final String ANGLE_ENABLED_APP = "angle_enabled_app";
+ public static final String GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE =
+ "angle_gl_driver_all_angle";
+
+ /**
+ * List of PKGs that have an OpenGL driver selected
+ * @hide
+ */
+ public static final String GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS =
+ "angle_gl_driver_selection_pkgs";
+
+ /**
+ * List of selected OpenGL drivers, corresponding to the PKGs in GLOBAL_SETTINGS_DRIVER_PKGS
+ * @hide
+ */
+ public static final String GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES =
+ "angle_gl_driver_selection_values";
/**
* App that is selected to use updated graphics driver.
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index b1a9866..06625b3 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -32,15 +32,16 @@
android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str());
}
-void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jboolean devOptIn,
+void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring devOptIn,
jobject rulesFd, jlong rulesOffset, jlong rulesLength) {
ScopedUtfChars pathChars(env, path);
ScopedUtfChars appNameChars(env, appName);
+ ScopedUtfChars devOptInChars(env, devOptIn);
int rulesFd_native = jniGetFDFromFileDescriptor(env, rulesFd);
android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
- devOptIn, rulesFd_native, rulesOffset, rulesLength);
+ devOptInChars.c_str(), rulesFd_native, rulesOffset, rulesLength);
}
void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) {
@@ -67,7 +68,7 @@
const JNINativeMethod g_methods[] = {
{ "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
{ "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
- { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;ZLjava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
+ { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
{ "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
{ "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) },
{ "setDebugLayersGLES", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayersGLES_native) },
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index ca8da55..da6e208 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -417,16 +417,20 @@
// Ordered GPU debug layer list for Vulkan
// i.e. <layer1>:<layer2>:...:<layerN>
optional SettingProto debug_layers = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
- // App will load ANGLE instead of native GLES drivers.
- optional SettingProto angle_enabled_app = 3;
+ // ANGLE - Force all PKGs to use ANGLE, regardless of any other settings
+ optional SettingProto angle_gl_driver_all_angle = 3;
+ // ANGLE - List of PKGs that specify an OpenGL driver
+ optional SettingProto angle_gl_driver_selection_pkgs = 4;
+ // ANGLE - Corresponding OpenGL driver selection for the PKG
+ optional SettingProto angle_gl_driver_selection_values = 5;
// App that can provide layer libraries.
- optional SettingProto debug_layer_app = 4;
+ optional SettingProto debug_layer_app = 6;
// Ordered GPU debug layer list for GLES
// i.e. <layer1>:<layer2>:...:<layerN>
- optional SettingProto debug_layers_gles = 5;
+ optional SettingProto debug_layers_gles = 7;
// App opt in to load updated graphics driver instead of
// native graphcis driver through developer options.
- optional SettingProto updated_gfx_driver_dev_opt_in_app = 6;
+ optional SettingProto updated_gfx_driver_dev_opt_in_app = 8;
}
optional Gpu gpu = 59;
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 1d72a03..79eaab8 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -470,7 +470,9 @@
Settings.Global.GPU_DEBUG_APP,
Settings.Global.GPU_DEBUG_LAYERS,
Settings.Global.GPU_DEBUG_LAYERS_GLES,
- Settings.Global.ANGLE_ENABLED_APP,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP,
Settings.Global.GPU_DEBUG_LAYER_APP,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 03eafc4..478ee54 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -51,6 +51,7 @@
<application
android:allowClearUserData="true"
android:label="@string/app_label"
+ android:icon="@drawable/ic_app_icon"
android:supportsRtl="true">
<service
diff --git a/packages/PrintSpooler/res/drawable/app_icon_foreground.xml b/packages/PrintSpooler/res/drawable/app_icon_foreground.xml
new file mode 100644
index 0000000..249e387
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/app_icon_foreground.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<inset
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetTop="25%"
+ android:insetRight="25%"
+ android:insetBottom="25%"
+ android:insetLeft="25%">
+
+ <vector
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M19,8L5,8c-1.66,0 -3,1.34 -3,3v6h4v4h12v-4h4v-6c0,-1.66 -1.34,-3 -3,-3zM16,19L8,19v-5h8v5zM19,12c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM18,3L6,3v4h12L18,3z" />
+ </vector>
+</inset>
diff --git a/packages/PrintSpooler/res/drawable/ic_app_icon.xml b/packages/PrintSpooler/res/drawable/ic_app_icon.xml
new file mode 100644
index 0000000..82c18e0
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/ic_app_icon.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@*android:color/accent_device_default_light"/>
+ <foreground android:drawable="@drawable/app_icon_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml b/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml
index 7e65848..a046332 100644
--- a/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml
+++ b/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml
@@ -20,7 +20,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
- android:tint="?android:attr/colorControlNormal">
+ android:tint="?android:attr/colorAccent">
<path
android:fillColor="#FF000000"
android:pathData="M20.49,19l-5.73,-5.73C15.53,12.2 16,10.91 16,9.5C16,5.91 13.09,3 9.5,3S3,5.91 3,9.5C3,13.09 5.91,16 9.5,16c1.41,0 2.7,-0.47 3.77,-1.24L19,20.49L20.49,19zM5,9.5C5,7.01 7.01,5 9.5,5S14,7.01 14,9.5S11.99,14 9.5,14S5,11.99 5,9.5z"/>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 9270d13..1bffff7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -71,15 +71,8 @@
boolean mJustDiscovered;
- private int mMessageRejectionCount;
-
private final Collection<Callback> mCallbacks = new ArrayList<>();
- // How many times user should reject the connection to make the choice persist.
- private final static int MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST = 2;
-
- private final static String MESSAGE_REJECTION_COUNT_PREFS_NAME = "bluetooth_message_reject";
-
/**
* Last time a bt profile auto-connect was attempted.
* If an ACTION_UUID intent comes in within
@@ -348,7 +341,6 @@
fetchActiveDevices();
migratePhonebookPermissionChoice();
migrateMessagePermissionChoice();
- fetchMessageRejectionCount();
dispatchAttributesChanged();
}
@@ -642,8 +634,6 @@
mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_UNKNOWN);
mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_UNKNOWN);
mDevice.setSimAccessPermission(BluetoothDevice.ACCESS_UNKNOWN);
- mMessageRejectionCount = 0;
- saveMessageRejectionCount();
}
refresh();
@@ -797,34 +787,6 @@
editor.commit();
}
- /**
- * @return Whether this rejection should persist.
- */
- public boolean checkAndIncreaseMessageRejectionCount() {
- if (mMessageRejectionCount < MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST) {
- mMessageRejectionCount++;
- saveMessageRejectionCount();
- }
- return mMessageRejectionCount >= MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST;
- }
-
- private void fetchMessageRejectionCount() {
- SharedPreferences preference = mContext.getSharedPreferences(
- MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE);
- mMessageRejectionCount = preference.getInt(mDevice.getAddress(), 0);
- }
-
- private void saveMessageRejectionCount() {
- SharedPreferences.Editor editor = mContext.getSharedPreferences(
- MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE).edit();
- if (mMessageRejectionCount == 0) {
- editor.remove(mDevice.getAddress());
- } else {
- editor.putInt(mDevice.getAddress(), mMessageRejectionCount);
- }
- editor.commit();
- }
-
private void processPhonebookAccess() {
if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) return;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
new file mode 100644
index 0000000..3520918
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.settings;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.ActivityManager;
+import android.content.IContentProvider;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
+import android.provider.Settings;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Receives shell commands from the command line related to device config flags, and dispatches them
+ * to the SettingsProvider.
+ *
+ * @hide
+ */
+@SystemApi
+public final class DeviceConfigService extends Binder {
+ /**
+ * TODO(b/113100523): Move this to DeviceConfig.java when it is added, and expose it as a System
+ * API.
+ */
+ private static final Uri CONFIG_CONTENT_URI =
+ Uri.parse("content://" + Settings.AUTHORITY + "/config");
+
+ final SettingsProvider mProvider;
+
+ public DeviceConfigService(SettingsProvider provider) {
+ mProvider = provider;
+ }
+
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+ (new MyShellCommand(mProvider)).exec(this, in, out, err, args, callback, resultReceiver);
+ }
+
+ static final class MyShellCommand extends ShellCommand {
+ final SettingsProvider mProvider;
+
+ enum CommandVerb {
+ UNSPECIFIED,
+ GET,
+ PUT,
+ DELETE,
+ LIST,
+ RESET,
+ }
+
+ MyShellCommand(SettingsProvider provider) {
+ mProvider = provider;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null || "help".equals(cmd) || "-h".equals(cmd)) {
+ onHelp();
+ return -1;
+ }
+
+ final PrintWriter perr = getErrPrintWriter();
+ boolean isValid = false;
+ CommandVerb verb;
+ if ("get".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.GET;
+ } else if ("put".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.PUT;
+ } else if ("delete".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.DELETE;
+ } else if ("list".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.LIST;
+ if (peekNextArg() == null) {
+ isValid = true;
+ }
+ } else if ("reset".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.RESET;
+ } else {
+ // invalid
+ perr.println("Invalid command: " + cmd);
+ return -1;
+ }
+
+ int resetMode = -1;
+ boolean makeDefault = false;
+ String namespace = null;
+ String key = null;
+ String value = null;
+ String arg = null;
+ while ((arg = getNextArg()) != null) {
+ if (verb == CommandVerb.RESET) {
+ if (resetMode == -1) {
+ if ("untrusted_defaults".equalsIgnoreCase(arg)) {
+ resetMode = Settings.RESET_MODE_UNTRUSTED_DEFAULTS;
+ } else if ("untrusted_clear".equalsIgnoreCase(arg)) {
+ resetMode = Settings.RESET_MODE_UNTRUSTED_CHANGES;
+ } else if ("trusted_defaults".equalsIgnoreCase(arg)) {
+ resetMode = Settings.RESET_MODE_TRUSTED_DEFAULTS;
+ } else {
+ // invalid
+ perr.println("Invalid reset mode: " + arg);
+ return -1;
+ }
+ if (peekNextArg() == null) {
+ isValid = true;
+ }
+ } else {
+ namespace = arg;
+ if (peekNextArg() == null) {
+ isValid = true;
+ } else {
+ // invalid
+ perr.println("Too many arguments");
+ return -1;
+ }
+ }
+ } else if (namespace == null) {
+ namespace = arg;
+ if (verb == CommandVerb.LIST) {
+ if (peekNextArg() == null) {
+ isValid = true;
+ } else {
+ // invalid
+ perr.println("Too many arguments");
+ return -1;
+ }
+ }
+ } else if (key == null) {
+ key = arg;
+ if ((verb == CommandVerb.GET || verb == CommandVerb.DELETE)) {
+ if (peekNextArg() == null) {
+ isValid = true;
+ } else {
+ // invalid
+ perr.println("Too many arguments");
+ return -1;
+ }
+ }
+ } else if (value == null) {
+ value = arg;
+ if (verb == CommandVerb.PUT && peekNextArg() == null) {
+ isValid = true;
+ }
+ } else if ("default".equalsIgnoreCase(arg)) {
+ makeDefault = true;
+ if (verb == CommandVerb.PUT && peekNextArg() == null) {
+ isValid = true;
+ } else {
+ // invalid
+ perr.println("Too many arguments");
+ return -1;
+ }
+ }
+ }
+
+ if (!isValid) {
+ perr.println("Bad arguments");
+ return -1;
+ }
+
+ final IContentProvider iprovider = mProvider.getIContentProvider();
+ final PrintWriter pout = getOutPrintWriter();
+ switch (verb) {
+ case GET:
+ pout.println(get(iprovider, namespace, key));
+ break;
+ case PUT:
+ put(iprovider, namespace, key, value, makeDefault);
+ break;
+ case DELETE:
+ pout.println(delete(iprovider, namespace, key)
+ ? "Successfully deleted " + key + " from " + namespace
+ : "Failed to delete " + key + " from " + namespace);
+ break;
+ case LIST:
+ for (String line : list(iprovider, namespace)) {
+ pout.println(line);
+ }
+ break;
+ case RESET:
+ reset(iprovider, resetMode, namespace);
+ break;
+ default:
+ perr.println("Unspecified command");
+ return -1;
+ }
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Device Config (device_config) commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println(" get NAMESPACE KEY");
+ pw.println(" Retrieve the current value of KEY from the given NAMESPACE.");
+ pw.println(" put NAMESPACE KEY VALUE [default]");
+ pw.println(" Change the contents of KEY to VALUE for the given NAMESPACE.");
+ pw.println(" {default} to set as the default value.");
+ pw.println(" delete NAMESPACE KEY");
+ pw.println(" Delete the entry for KEY for the given NAMESPACE.");
+ pw.println(" list [NAMESPACE]");
+ pw.println(" Print all keys and values defined, optionally for the given "
+ + "NAMESPACE.");
+ pw.println(" reset RESET_MODE [NAMESPACE]");
+ pw.println(" Reset all flag values, optionally for a NAMESPACE, according to "
+ + "RESET_MODE.");
+ pw.println(" RESET_MODE is one of {untrusted_defaults, untrusted_clear, "
+ + "trusted_defaults}");
+ pw.println(" NAMESPACE limits which flags are reset if provided, otherwise all "
+ + "flags are reset");
+ }
+
+ private String get(IContentProvider provider, String namespace, String key) {
+ String compositeKey = namespace + "/" + key;
+ String result = null;
+ try {
+ Bundle args = new Bundle();
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ Bundle b = provider.call(resolveCallingPackage(), Settings.CALL_METHOD_GET_CONFIG,
+ compositeKey, args);
+ if (b != null) {
+ result = b.getPairValue();
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
+ }
+ return result;
+ }
+
+ private void put(IContentProvider provider, String namespace, String key, String value,
+ boolean makeDefault) {
+ String compositeKey = namespace + "/" + key;
+
+ try {
+ Bundle args = new Bundle();
+ args.putString(Settings.NameValueTable.VALUE, value);
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ if (makeDefault) {
+ args.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true);
+ }
+ provider.call(resolveCallingPackage(), Settings.CALL_METHOD_PUT_CONFIG,
+ compositeKey, args);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
+ }
+ }
+
+ private boolean delete(IContentProvider provider, String namespace, String key) {
+ String compositeKey = namespace + "/" + key;
+ boolean success;
+
+ try {
+ Bundle args = new Bundle();
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ Bundle b = provider.call(resolveCallingPackage(),
+ Settings.CALL_METHOD_DELETE_CONFIG, compositeKey, args);
+ success = (b != null && b.getInt(SettingsProvider.RESULT_ROWS_DELETED) == 1);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
+ }
+ return success;
+ }
+
+ private List<String> list(IContentProvider provider, @Nullable String namespace) {
+ final ArrayList<String> lines = new ArrayList<>();
+
+ try {
+ Bundle args = new Bundle();
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ if (namespace != null) {
+ args.putString(Settings.CALL_METHOD_PREFIX_KEY, namespace);
+ }
+ Bundle b = provider.call(resolveCallingPackage(),
+ Settings.CALL_METHOD_LIST_CONFIG, null, args);
+ if (b != null) {
+ Map<String, String> flagsToValues =
+ (HashMap) b.getSerializable(Settings.NameValueTable.VALUE);
+ for (String key : flagsToValues.keySet()) {
+ lines.add(key + "=" + flagsToValues.get(key));
+ }
+ }
+
+ Collections.sort(lines);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
+ }
+ return lines;
+ }
+
+ private void reset(IContentProvider provider, int resetMode, @Nullable String namespace) {
+ try {
+ Bundle args = new Bundle();
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ args.putInt(Settings.CALL_METHOD_RESET_MODE_KEY, resetMode);
+ args.putString(Settings.CALL_METHOD_PREFIX_KEY, namespace);
+ provider.call(
+ resolveCallingPackage(), Settings.CALL_METHOD_RESET_CONFIG, null, args);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
+ }
+ }
+
+ private static String resolveCallingPackage() {
+ switch (Binder.getCallingUid()) {
+ case Process.ROOT_UID: {
+ return "root";
+ }
+
+ case Process.SHELL_UID: {
+ return "com.android.shell";
+ }
+
+ default: {
+ return null;
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 5e7fb85..533956f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -685,8 +685,14 @@
Settings.Global.GPU_DEBUG_LAYERS,
GlobalSettingsProto.Gpu.DEBUG_LAYERS);
dumpSetting(s, p,
- Settings.Global.ANGLE_ENABLED_APP,
- GlobalSettingsProto.Gpu.ANGLE_ENABLED_APP);
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
+ GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_ALL_ANGLE);
+ dumpSetting(s, p,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
+ GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_SELECTION_PKGS);
+ dumpSetting(s, p,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
+ GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_SELECTION_VALUES);
dumpSetting(s, p,
Settings.Global.GPU_DEBUG_LAYER_APP,
GlobalSettingsProto.Gpu.DEBUG_LAYER_APP);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 140a5a3..424368d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -335,6 +335,7 @@
startWatchingUserRestrictionChanges();
});
ServiceManager.addService("settings", new SettingsService(this));
+ ServiceManager.addService("device_config", new DeviceConfigService(this));
return true;
}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
new file mode 100644
index 0000000..59de6a7e
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.settings;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import libcore.io.Streams;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Tests for {@link DeviceConfigService}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class DeviceConfigServiceTest {
+ /**
+ * TODO(b/113100523): Move this to DeviceConfig.java when it is added, and expose it as a System
+ * API.
+ */
+ private static final Uri CONFIG_CONTENT_URI =
+ Uri.parse("content://" + Settings.AUTHORITY + "/config");
+ private static final String sNamespace = "namespace1";
+ private static final String sKey = "key1";
+ private static final String sValue = "value1";
+
+ private ContentResolver mContentResolver;
+
+ @Before
+ public void setUp() {
+ mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
+ }
+
+ @After
+ public void cleanUp() {
+ deleteFromContentProvider(mContentResolver, sNamespace, sKey);
+ }
+
+ @Test
+ public void testPut() throws Exception {
+ final String newNamespace = "namespace2";
+ final String newValue = "value2";
+
+ String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertNull(result);
+
+ try {
+ executeShellCommand("device_config put " + sNamespace + " " + sKey + " " + sValue);
+ executeShellCommand("device_config put " + newNamespace + " " + sKey + " " + newValue);
+
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertEquals(sValue, result);
+ result = getFromContentProvider(mContentResolver, newNamespace, sKey);
+ assertEquals(newValue, result);
+ } finally {
+ deleteFromContentProvider(mContentResolver, newNamespace, sKey);
+ }
+ }
+
+ @Test
+ public void testPut_invalidArgs() throws Exception {
+ // missing sNamespace
+ executeShellCommand("device_config put " + sKey + " " + sValue);
+ String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // still null
+ assertNull(result);
+
+ // too many arguments
+ executeShellCommand(
+ "device_config put " + sNamespace + " " + sKey + " " + sValue + " extra_arg");
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // still null
+ assertNull(result);
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ final String newNamespace = "namespace2";
+
+ putWithContentProvider(mContentResolver, sNamespace, sKey, sValue);
+ putWithContentProvider(mContentResolver, newNamespace, sKey, sValue);
+ String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertEquals(sValue, result);
+ result = getFromContentProvider(mContentResolver, newNamespace, sKey);
+ assertEquals(sValue, result);
+
+ try {
+ executeShellCommand("device_config delete " + sNamespace + " " + sKey);
+ // sKey is deleted from sNamespace
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertNull(result);
+ // sKey is not deleted from newNamespace
+ result = getFromContentProvider(mContentResolver, newNamespace, sKey);
+ assertEquals(sValue, result);
+ } finally {
+ deleteFromContentProvider(mContentResolver, newNamespace, sKey);
+ }
+ }
+
+ @Test
+ public void testDelete_invalidArgs() throws Exception {
+ putWithContentProvider(mContentResolver, sNamespace, sKey, sValue);
+ String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertEquals(sValue, result);
+
+ // missing sNamespace
+ executeShellCommand("device_config delete " + sKey);
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // sValue was not deleted
+ assertEquals(sValue, result);
+
+ // too many arguments
+ executeShellCommand("device_config delete " + sNamespace + " " + sKey + " extra_arg");
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // sValue was not deleted
+ assertEquals(sValue, result);
+ }
+
+ @Test
+ public void testReset_setUntrustedDefault() throws Exception {
+ String newValue = "value2";
+
+ // make sValue the untrusted default (set by root)
+ executeShellCommand(
+ "device_config put " + sNamespace + " " + sKey + " " + sValue + " default");
+ // make newValue the current value
+ executeShellCommand(
+ "device_config put " + sNamespace + " " + sKey + " " + newValue);
+ String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertEquals(newValue, result);
+
+ executeShellCommand("device_config reset untrusted_defaults " + sNamespace);
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // back to the default
+ assertEquals(sValue, result);
+
+ executeShellCommand("device_config reset trusted_defaults " + sNamespace);
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // not trusted default was set
+ assertNull(result);
+ }
+
+ @Test
+ public void testReset_setTrustedDefault() throws Exception {
+ String newValue = "value2";
+
+ // make sValue the trusted default (set by system)
+ putWithContentProvider(mContentResolver, sNamespace, sKey, sValue, true);
+ // make newValue the current value
+ executeShellCommand(
+ "device_config put " + sNamespace + " " + sKey + " " + newValue);
+ String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertEquals(newValue, result);
+
+ executeShellCommand("device_config reset untrusted_defaults " + sNamespace);
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // back to the default
+ assertEquals(sValue, result);
+
+ executeShellCommand("device_config reset trusted_defaults " + sNamespace);
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // our trusted default is still set
+ assertEquals(sValue, result);
+ }
+
+ private static void executeShellCommand(String command) throws IOException {
+ InputStream is = new FileInputStream(InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation().executeShellCommand(command).getFileDescriptor());
+ Streams.readFully(is);
+ }
+
+ private static void putWithContentProvider(ContentResolver resolver, String namespace,
+ String key, String value) {
+ putWithContentProvider(resolver, namespace, key, value, false);
+ }
+
+ private static void putWithContentProvider(ContentResolver resolver, String namespace,
+ String key, String value, boolean makeDefault) {
+ String compositeName = namespace + "/" + key;
+ Bundle args = new Bundle();
+ args.putString(Settings.NameValueTable.VALUE, value);
+ if (makeDefault) {
+ args.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true);
+ }
+ resolver.call(
+ CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, compositeName, args);
+ }
+
+ private static String getFromContentProvider(ContentResolver resolver, String namespace,
+ String key) {
+ String compositeName = namespace + "/" + key;
+ Bundle result = resolver.call(
+ CONFIG_CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, compositeName, null);
+ assertNotNull(result);
+ return result.getString(Settings.NameValueTable.VALUE);
+ }
+
+ private static boolean deleteFromContentProvider(ContentResolver resolver, String namespace,
+ String key) {
+ String compositeName = namespace + "/" + key;
+ Bundle result = resolver.call(
+ CONFIG_CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, compositeName, null);
+ assertNotNull(result);
+ return compositeName.equals(result.getString(Settings.NameValueTable.VALUE));
+ }
+}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e564711..5fe08aab9 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -51,6 +51,7 @@
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.REORDER_TASKS" />
+ <uses-permission android:name="android.permission.REMOVE_TASKS" />
<uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
<uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8e0bfb6..b6c9b8c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -23,6 +23,8 @@
<dimen name="navigation_bar_size">@*android:dimen/navigation_bar_height</dimen>
<!-- Minimum swipe distance to catch the swipe gestures to invoke assist or switch tasks. -->
<dimen name="navigation_bar_min_swipe_distance">48dp</dimen>
+ <!-- The distance from a side of device of the navigation bar to start an edge swipe -->
+ <dimen name="navigation_bar_edge_swipe_threshold">60dp</dimen>
<!-- thickness (height) of the dead zone at the top of the navigation bar,
reducing false presses on navbar buttons; approx 2mm -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 451297b..cc27135 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -17,9 +17,10 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_CLICK;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_LONG_PRESS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_SECONDARY_CLICK;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CONTEXT;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_IS_FULL_QS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_POSITION;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_VALUE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_BAR_STATE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
@@ -52,6 +53,7 @@
import com.android.systemui.qs.PagedTileLayout.TilePage;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QuickStatusBarHeader;
+import com.android.systemui.statusbar.StatusBarStateController;
import java.util.ArrayList;
@@ -61,6 +63,8 @@
* State management done on a looper provided by the host. Tiles should update state in
* handleUpdateState. Callbacks affecting state should use refreshState to trigger another
* state update pass on tile looper.
+ *
+ * @param <TState> see above
*/
public abstract class QSTileImpl<TState extends State> implements QSTile {
protected final String TAG = "Tile." + getClass().getSimpleName();
@@ -76,6 +80,8 @@
protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
private final ArraySet<Object> mListeners = new ArraySet<>();
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+ private final StatusBarStateController
+ mStatusBarStateController = Dependency.get(StatusBarStateController.class);
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
private final Object mStaleListener = new Object();
@@ -172,17 +178,23 @@
}
public void click() {
- mMetricsLogger.write(populate(new LogMaker(ACTION_QS_CLICK).setType(TYPE_ACTION)));
+ mMetricsLogger.write(populate(new LogMaker(ACTION_QS_CLICK).setType(TYPE_ACTION)
+ .addTaggedData(FIELD_STATUS_BAR_STATE,
+ mStatusBarStateController.getState())));
mHandler.sendEmptyMessage(H.CLICK);
}
public void secondaryClick() {
- mMetricsLogger.write(populate(new LogMaker(ACTION_QS_SECONDARY_CLICK).setType(TYPE_ACTION)));
+ mMetricsLogger.write(populate(new LogMaker(ACTION_QS_SECONDARY_CLICK).setType(TYPE_ACTION)
+ .addTaggedData(FIELD_STATUS_BAR_STATE,
+ mStatusBarStateController.getState())));
mHandler.sendEmptyMessage(H.SECONDARY_CLICK);
}
public void longClick() {
- mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION)));
+ mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION)
+ .addTaggedData(FIELD_STATUS_BAR_STATE,
+ mStatusBarStateController.getState())));
mHandler.sendEmptyMessage(H.LONG_CLICK);
Prefs.putInt(
@@ -196,7 +208,7 @@
logMaker.addTaggedData(FIELD_QS_VALUE, ((BooleanState) mState).value ? 1 : 0);
}
return logMaker.setSubtype(getMetricsCategory())
- .addTaggedData(FIELD_CONTEXT, mIsFullQs)
+ .addTaggedData(FIELD_IS_FULL_QS, mIsFullQs)
.addTaggedData(FIELD_QS_POSITION, mHost.indexOf(mTileSpec));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
index b83ebc7..9c8b1b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
@@ -56,6 +56,11 @@
}
@Override
+ public boolean allowHitTargetToMoveOverDrag() {
+ return true;
+ }
+
+ @Override
public boolean canPerformAction() {
return mProxySender.getBackButtonAlpha() > 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index cd6e1d7..a0021ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -63,6 +63,7 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.Interpolators;
@@ -96,7 +97,6 @@
final static boolean ALTERNATE_CAR_MODE_UI = false;
- final Display mDisplay;
View mCurrentView = null;
View[] mRotatedViews = new View[4];
@@ -154,6 +154,7 @@
private QuickScrubAction mQuickScrubAction;
private QuickStepAction mQuickStepAction;
private NavigationBackAction mBackAction;
+ private QuickSwitchAction mQuickSwitchAction;
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -281,8 +282,6 @@
public NavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
- mDisplay = context.getDisplay();
-
mVertical = false;
mLongClickableAccessibilityButton = false;
@@ -326,9 +325,10 @@
mQuickScrubAction = new QuickScrubAction(this, mOverviewProxyService);
mQuickStepAction = new QuickStepAction(this, mOverviewProxyService);
mBackAction = new NavigationBackAction(this, mOverviewProxyService);
+ mQuickSwitchAction = new QuickSwitchAction(this, mOverviewProxyService);
mDefaultGestureMap = new NavigationGestureAction[] {
mQuickStepAction, null /* swipeDownAction*/, null /* swipeLeftAction */,
- mQuickScrubAction
+ mQuickScrubAction, null /* swipeLeftEdgeAction */, null /* swipeRightEdgeAction */
};
mPrototypeController = new NavigationPrototypeController(mHandler, mContext);
@@ -359,7 +359,9 @@
getNavigationActionFromType(assignedMap[0], mDefaultGestureMap[0]),
getNavigationActionFromType(assignedMap[1], mDefaultGestureMap[1]),
getNavigationActionFromType(assignedMap[2], mDefaultGestureMap[2]),
- getNavigationActionFromType(assignedMap[3], mDefaultGestureMap[3]));
+ getNavigationActionFromType(assignedMap[3], mDefaultGestureMap[3]),
+ getNavigationActionFromType(assignedMap[4], mDefaultGestureMap[4]),
+ getNavigationActionFromType(assignedMap[5], mDefaultGestureMap[5]));
}
}
@@ -372,6 +374,8 @@
return mQuickScrubAction;
case NavigationPrototypeController.ACTION_BACK:
return mBackAction;
+ case NavigationPrototypeController.ACTION_QUICKSWITCH:
+ return mQuickSwitchAction;
default:
return defaultAction;
}
@@ -652,8 +656,8 @@
Log.i(TAG, "updateNavButtonIcons (b/113914868): home disabled=" + disableHome
+ " mDisabledFlags=" + mDisabledFlags);
- // Always disable recents when alternate car mode UI is active.
- boolean disableRecent = mUseCarModeUi || !isOverviewEnabled();
+ // Always disable recents when alternate car mode UI is active and for secondary displays.
+ boolean disableRecent = isRecentsButtonDisabled();
boolean disableBack = QuickStepController.shouldhideBackButton(getContext())
|| (((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0) && !useAltBack);
@@ -689,6 +693,16 @@
getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
}
+ @VisibleForTesting
+ boolean isRecentsButtonDisabled() {
+ return mUseCarModeUi || !isOverviewEnabled()
+ || getContext().getDisplayId() != Display.DEFAULT_DISPLAY;
+ }
+
+ private Display getContextDisplay() {
+ return getContext().getDisplay();
+ }
+
public boolean inScreenPinning() {
return ActivityManagerWrapper.getInstance().isScreenPinningActive();
}
@@ -890,7 +904,7 @@
}
private void updateCurrentView() {
- final int rot = mDisplay.getRotation();
+ final int rot = getContextDisplay().getRotation();
for (int i=0; i<4; i++) {
mRotatedViews[i].setVisibility(View.GONE);
}
@@ -954,7 +968,7 @@
int navBarPos = NAV_BAR_INVALID;
try {
navBarPos = WindowManagerGlobal.getWindowManagerService().getNavBarPosition(
- mDisplay.getDisplayId());
+ getContext().getDisplayId());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get nav bar position.", e);
}
@@ -1128,7 +1142,7 @@
pw.println("NavigationBarView {");
final Rect r = new Rect();
final Point size = new Point();
- mDisplay.getRealSize(size);
+ getContextDisplay().getRealSize(size);
pw.println(String.format(" this: " + StatusBar.viewInfo(this)
+ " " + visibilityToString(getVisibility())));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
index a8d00c4..8c57fc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
@@ -112,7 +112,7 @@
/**
* @return whether or not to move the button that started gesture over with user input drag
*/
- public boolean requiresDragWithHitTarget() {
+ public boolean allowHitTargetToMoveOverDrag() {
return false;
}
@@ -139,9 +139,9 @@
* Tell if action is enabled. Compared to {@link #canPerformAction()} this is based on settings
* if the action is disabled for a particular gesture. For example a back action can be enabled
* however if there is nothing to back to then {@link #canPerformAction()} should return false.
- * In this way if the action requires {@link #requiresDragWithHitTarget()} then if enabled, the
- * button can be dragged with a large dampening factor during the gesture but will not activate
- * the action.
+ * In this way if the action requires {@link #allowHitTargetToMoveOverDrag()} then if enabled,
+ * the button can be dragged with a large dampening factor during the gesture but will not
+ * activate the action.
* @return true if this action is enabled and can run
*/
public abstract boolean isEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index e8c0bf1..b11b6d47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -24,7 +24,6 @@
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
-import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -46,6 +45,7 @@
static final int ACTION_QUICKSTEP = 1;
static final int ACTION_QUICKSCRUB = 2;
static final int ACTION_BACK = 3;
+ static final int ACTION_QUICKSWITCH = 4;
private OnPrototypeChangedListener mListener;
@@ -53,7 +53,7 @@
* Each index corresponds to a different action set in QuickStepController
* {@see updateSwipeLTRBackSetting}
*/
- private int[] mActionMap = new int[4];
+ private int[] mActionMap = new int[6];
private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubAction.java
index 2b202eb..bbfd51a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubAction.java
@@ -18,8 +18,6 @@
import static com.android.systemui.Interpolators.ALPHA_IN;
import static com.android.systemui.Interpolators.ALPHA_OUT;
-import static com.android.systemui.recents.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
-import static com.android.systemui.recents.OverviewProxyService.TAG_OPS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -31,11 +29,8 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RadialGradient;
-import android.graphics.Rect;
import android.graphics.Shader;
-import android.os.RemoteException;
import android.util.FloatProperty;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
@@ -46,7 +41,7 @@
/**
* QuickScrub action to send to launcher to start quickscrub gesture
*/
-public class QuickScrubAction extends NavigationGestureAction {
+public class QuickScrubAction extends QuickSwitchAction {
private static final String TAG = "QuickScrubAction";
private static final float TRACK_SCALE = 0.95f;
@@ -65,7 +60,6 @@
private final int mTrackThickness;
private final int mTrackEndPadding;
private final Paint mTrackPaint = new Paint();
- private final Rect mTrackRect = new Rect();
private final FloatProperty<QuickScrubAction> mTrackAlphaProperty =
new FloatProperty<QuickScrubAction>("TrackAlpha") {
@@ -177,7 +171,7 @@
x1 = mNavigationBarView.getPaddingStart() + mTrackEndPadding;
x2 = x1 + width - 2 * mTrackEndPadding;
}
- mTrackRect.set(x1, y1, x2, y2);
+ mDragOverRect.set(x1, y1, x2, y2);
}
@Override
@@ -194,15 +188,16 @@
mTrackPaint.setAlpha(Math.round(255f * mTrackAlpha));
// Scale the track, but apply the inverse scale from the nav bar
- final float radius = mTrackRect.height() / 2;
+ final float radius = mDragOverRect.height() / 2;
canvas.save();
- float translate = Utilities.clamp(mHighlightCenter, mTrackRect.left, mTrackRect.right);
+ float translate = Utilities.clamp(mHighlightCenter, mDragOverRect.left,
+ mDragOverRect.right);
canvas.translate(translate, 0);
canvas.scale(mTrackScale / mNavigationBarView.getScaleX(),
1f / mNavigationBarView.getScaleY(),
- mTrackRect.centerX(), mTrackRect.centerY());
- canvas.drawRoundRect(mTrackRect.left - translate, mTrackRect.top,
- mTrackRect.right - translate, mTrackRect.bottom, radius, radius, mTrackPaint);
+ mDragOverRect.centerX(), mDragOverRect.centerY());
+ canvas.drawRoundRect(mDragOverRect.left - translate, mDragOverRect.top,
+ mDragOverRect.right - translate, mDragOverRect.bottom, radius, radius, mTrackPaint);
canvas.restore();
}
@@ -212,11 +207,6 @@
}
@Override
- public boolean disableProxyEvents() {
- return true;
- }
-
- @Override
protected void onGestureStart(MotionEvent event) {
updateHighlight();
ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
@@ -231,42 +221,12 @@
mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
mTrackAnimator.start();
- // Disable slippery for quick scrub to not cancel outside the nav bar
- mNavigationBarView.updateSlippery();
-
- try {
- mProxySender.getProxy().onQuickScrubStart();
- if (DEBUG_OVERVIEW_PROXY) {
- Log.d(TAG_OPS, "Quick Scrub Start");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send start of quick scrub.", e);
- }
- mProxySender.notifyQuickScrubStarted();
+ startQuickGesture(event);
}
@Override
public void onGestureMove(int x, int y) {
- int trackSize, offset;
- if (isNavBarVertical()) {
- trackSize = mTrackRect.height();
- offset = y - mTrackRect.top;
- } else {
- offset = x - mTrackRect.left;
- trackSize = mTrackRect.width();
- }
- if (!mDragHorizontalPositive || !mDragVerticalPositive) {
- offset -= isNavBarVertical() ? mTrackRect.height() : mTrackRect.width();
- }
- float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
- try {
- mProxySender.getProxy().onQuickScrubProgress(scrubFraction);
- if (DEBUG_OVERVIEW_PROXY) {
- Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send progress of quick scrub.", e);
- }
+ super.onGestureMove(x, y);
mHighlightCenter = x;
mNavigationBarView.invalidate();
}
@@ -278,14 +238,7 @@
private void endQuickScrub(boolean animate) {
animateEnd();
- try {
- mProxySender.getProxy().onQuickScrubEnd();
- if (DEBUG_OVERVIEW_PROXY) {
- Log.d(TAG_OPS, "Quick Scrub End");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send end of quick scrub.", e);
- }
+ endQuickGesture(animate);
if (!animate) {
if (mTrackAnimator != null) {
mTrackAnimator.end();
@@ -295,7 +248,7 @@
}
private void updateHighlight() {
- if (mTrackRect.isEmpty()) {
+ if (mDragOverRect.isEmpty()) {
return;
}
int colorBase, colorGrad;
@@ -306,8 +259,8 @@
colorBase = getContext().getColor(R.color.quick_step_track_background_background_light);
colorGrad = getContext().getColor(R.color.quick_step_track_background_foreground_light);
}
- final RadialGradient mHighlight = new RadialGradient(0, mTrackRect.height() / 2,
- mTrackRect.width() * GRADIENT_WIDTH, colorGrad, colorBase,
+ final RadialGradient mHighlight = new RadialGradient(0, mDragOverRect.height() / 2,
+ mDragOverRect.width() * GRADIENT_WIDTH, colorGrad, colorBase,
Shader.TileMode.CLAMP);
mTrackPaint.setShader(mHighlight);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index 4983618..9eb5737a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -76,7 +76,9 @@
private static final int ACTION_SWIPE_DOWN_INDEX = 1;
private static final int ACTION_SWIPE_LEFT_INDEX = 2;
private static final int ACTION_SWIPE_RIGHT_INDEX = 3;
- private static final int MAX_GESTURES = 4;
+ private static final int ACTION_SWIPE_LEFT_FROM_EDGE_INDEX = 4;
+ private static final int ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX = 5;
+ private static final int MAX_GESTURES = 6;
private NavigationBarView mNavigationBarView;
@@ -97,6 +99,7 @@
private float mMaxDragLimit;
private float mMinDragLimit;
private float mDragDampeningFactor;
+ private float mEdgeSwipeThreshold;
private NavigationGestureAction mCurrentAction;
private NavigationGestureAction[] mGestureActions = new NavigationGestureAction[MAX_GESTURES];
@@ -128,15 +131,21 @@
* @param swipeDownAction action after swiping down
* @param swipeLeftAction action after swiping left
* @param swipeRightAction action after swiping right
+ * @param swipeLeftFromEdgeAction action swiping left starting from the right side
+ * @param swipeRightFromEdgeAction action swiping right starting from the left side
*/
public void setGestureActions(@Nullable NavigationGestureAction swipeUpAction,
@Nullable NavigationGestureAction swipeDownAction,
@Nullable NavigationGestureAction swipeLeftAction,
- @Nullable NavigationGestureAction swipeRightAction) {
+ @Nullable NavigationGestureAction swipeRightAction,
+ @Nullable NavigationGestureAction swipeLeftFromEdgeAction,
+ @Nullable NavigationGestureAction swipeRightFromEdgeAction) {
mGestureActions[ACTION_SWIPE_UP_INDEX] = swipeUpAction;
mGestureActions[ACTION_SWIPE_DOWN_INDEX] = swipeDownAction;
mGestureActions[ACTION_SWIPE_LEFT_INDEX] = swipeLeftAction;
mGestureActions[ACTION_SWIPE_RIGHT_INDEX] = swipeRightAction;
+ mGestureActions[ACTION_SWIPE_LEFT_FROM_EDGE_INDEX] = swipeLeftFromEdgeAction;
+ mGestureActions[ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX] = swipeRightFromEdgeAction;
// Set the current state to all actions
for (NavigationGestureAction action: mGestureActions) {
@@ -233,6 +242,8 @@
mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
mAllowGestureDetection = true;
mNotificationsVisibleOnDown = !mNavigationBarView.isNotificationsFullyCollapsed();
+ mEdgeSwipeThreshold = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.navigation_bar_edge_swipe_threshold);
break;
}
case MotionEvent.ACTION_MOVE: {
@@ -284,13 +295,17 @@
}
} else if (exceededSwipeHorizontalTouchSlop) {
if (mDragHPositive ? (posH < touchDownH) : (posH > touchDownH)) {
- // Swiping left (ltr) gesture
- tryToStartGesture(mGestureActions[ACTION_SWIPE_LEFT_INDEX],
- true /* alignedWithNavBar */, event);
+ // Swiping left (rtl) gesture
+ int index = isEdgeSwipeAlongNavBar(touchDownH, !mDragHPositive)
+ ? ACTION_SWIPE_LEFT_FROM_EDGE_INDEX : ACTION_SWIPE_LEFT_INDEX;
+ tryToStartGesture(mGestureActions[index], true /* alignedWithNavBar */,
+ event);
} else {
// Swiping right (ltr) gesture
- tryToStartGesture(mGestureActions[ACTION_SWIPE_RIGHT_INDEX],
- true /* alignedWithNavBar */, event);
+ int index = isEdgeSwipeAlongNavBar(touchDownH, mDragHPositive)
+ ? ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX : ACTION_SWIPE_RIGHT_INDEX;
+ tryToStartGesture(mGestureActions[index], true /* alignedWithNavBar */,
+ event);
}
}
}
@@ -333,6 +348,17 @@
return mCurrentAction != null || deadZoneConsumed;
}
+ private boolean isEdgeSwipeAlongNavBar(int touchDown, boolean dragPositiveDirection) {
+ // Detect edge swipe from side of 0 -> threshold
+ if (dragPositiveDirection) {
+ return touchDown < mEdgeSwipeThreshold;
+ }
+ // Detect edge swipe from side of size -> (size - threshold)
+ final int largeSide = isNavBarVertical()
+ ? mNavigationBarView.getHeight() : mNavigationBarView.getWidth();
+ return touchDown > largeSide - mEdgeSwipeThreshold;
+ }
+
private void handleDragHitTarget(int position, int touchDown) {
// Drag the hit target if gesture action requires it
if (mHitTarget != null && (mGestureVerticalDragsButton || mGestureHorizontalDragsButton)) {
@@ -480,7 +506,7 @@
event.transform(mTransformLocalMatrix);
// Calculate the bounding limits of drag to avoid dragging off nav bar's window
- if (action.requiresDragWithHitTarget() && mHitTarget != null) {
+ if (action.allowHitTargetToMoveOverDrag() && mHitTarget != null) {
final int[] buttonCenter = new int[2];
View button = mHitTarget.getCurrentView();
button.getLocationInWindow(buttonCenter);
@@ -505,7 +531,7 @@
// Handle direction of the hit target drag from the axis that started the gesture
// Also calculate the dampening factor, weaker dampening if there is an active action
- if (action.requiresDragWithHitTarget()) {
+ if (action.allowHitTargetToMoveOverDrag()) {
if (alignedWithNavBar) {
mGestureHorizontalDragsButton = true;
mGestureVerticalDragsButton = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSwitchAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSwitchAction.java
new file mode 100644
index 0000000..40f2392
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSwitchAction.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.android.systemui.recents.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
+import static com.android.systemui.recents.OverviewProxyService.TAG_OPS;
+
+import android.annotation.NonNull;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.shared.recents.utilities.Utilities;
+
+/**
+ * QuickSwitch action to send to launcher
+ */
+public class QuickSwitchAction extends NavigationGestureAction {
+ private static final String TAG = "QuickSwitchAction";
+ private static final String QUICKSWITCH_ENABLED_SETTING = "QUICK_SWITCH";
+
+ protected final Rect mDragOverRect = new Rect();
+
+ public QuickSwitchAction(@NonNull NavigationBarView navigationBar,
+ @NonNull OverviewProxyService service) {
+ super(navigationBar, service);
+ }
+
+ @Override
+ public void setBarState(boolean changed, int navBarPos, boolean dragHorPositive,
+ boolean dragVerPositive) {
+ super.setBarState(changed, navBarPos, dragHorPositive, dragVerPositive);
+ if (changed && isActive()) {
+ // End quickscrub if the state changes mid-transition
+ endQuickGesture(false /* animate */);
+ }
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return mNavigationBarView.isQuickScrubEnabled();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ mDragOverRect.set(top, left, right, bottom);
+ }
+
+ @Override
+ public boolean disableProxyEvents() {
+ return true;
+ }
+
+ @Override
+ protected void onGestureStart(MotionEvent event) {
+ // Temporarily enable launcher to allow quick switch instead of quick scrub
+ Settings.Global.putInt(mNavigationBarView.getContext().getContentResolver(),
+ QUICKSWITCH_ENABLED_SETTING, 1 /* enabled */);
+
+ startQuickGesture(event);
+ }
+
+ @Override
+ public void onGestureMove(int x, int y) {
+ int dragLength, offset;
+ if (isNavBarVertical()) {
+ dragLength = mDragOverRect.height();
+ offset = y - mDragOverRect.top;
+ } else {
+ offset = x - mDragOverRect.left;
+ dragLength = mDragOverRect.width();
+ }
+ if (!mDragHorizontalPositive || !mDragVerticalPositive) {
+ offset -= dragLength;
+ }
+ float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / dragLength, 0, 1);
+ try {
+ mProxySender.getProxy().onQuickScrubProgress(scrubFraction);
+ if (DEBUG_OVERVIEW_PROXY) {
+ Log.d(TAG_OPS, "Quick Switch Progress:" + scrubFraction);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send progress of quick switch.", e);
+ }
+ }
+
+ @Override
+ protected void onGestureEnd() {
+ endQuickGesture(true /* animate */);
+
+ // Disable launcher to use quick switch instead of quick scrub
+ Settings.Global.putInt(mNavigationBarView.getContext().getContentResolver(),
+ QUICKSWITCH_ENABLED_SETTING, 0 /* disabled */);
+ }
+
+ protected void startQuickGesture(MotionEvent event) {
+ // Disable slippery for quick scrub to not cancel outside the nav bar
+ mNavigationBarView.updateSlippery();
+
+ try {
+ mProxySender.getProxy().onQuickScrubStart();
+ if (DEBUG_OVERVIEW_PROXY) {
+ Log.d(TAG_OPS, "Quick Scrub Start");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send start of quick scrub.", e);
+ }
+ mProxySender.notifyQuickScrubStarted();
+ }
+
+ protected void endQuickGesture(boolean animate) {
+ try {
+ mProxySender.getProxy().onQuickScrubEnd();
+ if (DEBUG_OVERVIEW_PROXY) {
+ Log.d(TAG_OPS, "Quick Scrub End");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send end of quick scrub.", e);
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
index e811270..f792d7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
@@ -18,6 +18,7 @@
import android.testing.LeakCheck;
import android.testing.TestableContext;
import android.util.ArrayMap;
+import android.view.Display;
public class SysuiTestableContext extends TestableContext implements SysUiServiceProvider {
@@ -47,4 +48,15 @@
if (mComponents == null) mComponents = new ArrayMap<>();
mComponents.put(interfaceType, component);
}
+
+ @Override
+ public Context createDisplayContext(Display display) {
+ if (display == null) {
+ throw new IllegalArgumentException("display must not be null");
+ }
+
+ SysuiTestableContext context =
+ new SysuiTestableContext(getBaseContext().createDisplayContext(display));
+ return context;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 6764634..e5464e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -19,8 +19,10 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_SECONDARY_CLICK;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_POSITION;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_VALUE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_BAR_STATE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -37,7 +39,6 @@
import android.content.Intent;
import android.metrics.LogMaker;
import android.support.test.filters.SmallTest;
-import android.support.test.InstrumentationRegistry;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -48,12 +49,17 @@
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
+import org.mockito.Captor;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -65,13 +71,20 @@
private TileImpl mTile;
private QSTileHost mHost;
private MetricsLogger mMetricsLogger;
+ private StatusBarStateController mStatusBarStateController;
+
+ @Captor
+ private ArgumentCaptor<LogMaker> mLogCaptor;
@Before
public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
String spec = "spec";
mTestableLooper = TestableLooper.get(this);
mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
+ mStatusBarStateController =
+ mDependency.injectMockDependency(StatusBarStateController.class);
mHost = mock(QSTileHost.class);
when(mHost.indexOf(spec)).thenReturn(POSITION);
when(mHost.getContext()).thenReturn(mContext.getBaseContext());
@@ -88,19 +101,57 @@
}
@Test
+ public void testClick_Metrics_Status_Bar_Status() {
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
+ mTile.click();
+ verify(mMetricsLogger).write(mLogCaptor.capture());
+ assertEquals(StatusBarState.SHADE, mLogCaptor.getValue()
+ .getTaggedData(FIELD_STATUS_BAR_STATE));
+ }
+
+ @Test
public void testSecondaryClick_Metrics() {
mTile.secondaryClick();
verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_SECONDARY_CLICK)));
}
@Test
+ public void testSecondaryClick_Metrics_Status_Bar_Status() {
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
+ mTile.secondaryClick();
+ verify(mMetricsLogger).write(mLogCaptor.capture());
+ assertEquals(StatusBarState.KEYGUARD, mLogCaptor.getValue()
+ .getTaggedData(FIELD_STATUS_BAR_STATE));
+ }
+
+ @Test
public void testLongClick_Metrics() {
mTile.longClick();
verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_LONG_PRESS)));
}
@Test
- public void testPopulate() {
+ public void testLongClick_Metrics_Status_Bar_Status() {
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
+ mTile.click();
+ verify(mMetricsLogger).write(mLogCaptor.capture());
+ assertEquals(StatusBarState.SHADE_LOCKED, mLogCaptor.getValue()
+ .getTaggedData(FIELD_STATUS_BAR_STATE));
+ }
+
+ @Test
+ public void testPopulateWithLockedScreen() {
+ LogMaker maker = mock(LogMaker.class);
+ when(maker.setSubtype(anyInt())).thenReturn(maker);
+ when(maker.addTaggedData(anyInt(), any())).thenReturn(maker);
+ mTile.getState().value = true;
+ mTile.populate(maker);
+ verify(maker).addTaggedData(eq(FIELD_QS_VALUE), eq(1));
+ verify(maker).addTaggedData(eq(FIELD_QS_POSITION), eq(POSITION));
+ }
+
+ @Test
+ public void testPopulateWithUnlockedScreen() {
LogMaker maker = mock(LogMaker.class);
when(maker.setSubtype(anyInt())).thenReturn(maker);
when(maker.addTaggedData(anyInt(), any())).thenReturn(maker);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
new file mode 100644
index 0000000..73f3b43
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.ImageReader;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.Display;
+import android.view.DisplayInfo;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.SysuiTestableContext;
+import com.android.systemui.statusbar.CommandQueue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** atest NavigationBarButtonTest */
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class NavigationBarButtonTest extends SysuiTestCase {
+
+ private ImageReader mReader;
+ private NavigationBarView mNavBar;
+ private VirtualDisplay mVirtualDisplay;
+
+ @Before
+ public void setup() {
+ final Display display = createVirtualDisplay();
+ final SysuiTestableContext context =
+ (SysuiTestableContext) mContext.createDisplayContext(display);
+ context.putComponent(CommandQueue.class, mock(CommandQueue.class));
+
+ mNavBar = new NavigationBarView(context, null);
+ }
+
+ private Display createVirtualDisplay() {
+ final String displayName = "NavVirtualDisplay";
+ final DisplayInfo displayInfo = new DisplayInfo();
+ mContext.getDisplay().getDisplayInfo(displayInfo);
+
+ final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+
+ mReader = ImageReader.newInstance(displayInfo.logicalWidth,
+ displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2);
+
+ assertNotNull("ImageReader must not be null", mReader);
+
+ mVirtualDisplay = displayManager.createVirtualDisplay(displayName, displayInfo.logicalWidth,
+ displayInfo.logicalHeight, displayInfo.logicalDensityDpi, mReader.getSurface(),
+ 0 /*flags*/);
+
+ assertNotNull("virtual display must not be null", mVirtualDisplay);
+
+ return mVirtualDisplay.getDisplay();
+ }
+
+ @After
+ public void tearDown() {
+ releaseDisplay();
+ }
+
+ private void releaseDisplay() {
+ mVirtualDisplay.release();
+ mReader.close();
+ }
+
+ @Test
+ public void testRecentsButtonDisabledOnSecondaryDisplay() {
+ assertTrue("The recents button must be disabled",
+ mNavBar.isRecentsButtonDisabled());
+ }
+}
+
+
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
index cdaa242..abb8c79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
@@ -61,6 +61,10 @@
@RunWithLooper
@SmallTest
public class QuickStepControllerTest extends SysuiTestCase {
+ private static final int NAVBAR_WIDTH = 1000;
+ private static final int NAVBAR_HEIGHT = 300;
+ private static final int EDGE_THRESHOLD = 100;
+
private QuickStepController mController;
private NavigationBarView mNavigationBarView;
private StatusBar mStatusBar;
@@ -73,6 +77,8 @@
MockitoAnnotations.initMocks(this);
final ButtonDispatcher backButton = mock(ButtonDispatcher.class);
mResources = mock(Resources.class);
+ doReturn(EDGE_THRESHOLD).when(mResources)
+ .getDimensionPixelSize(R.dimen.navigation_bar_edge_swipe_threshold);
mProxyService = mock(OverviewProxyService.class);
mProxy = mock(IOverviewProxy.Stub.class);
@@ -109,7 +115,8 @@
public void testNoGesturesWhenSwipeUpDisabled() throws Exception {
doReturn(false).when(mProxyService).shouldShowSwipeUpUI();
mController.setGestureActions(mockAction(true), null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
MotionEvent ev = event(MotionEvent.ACTION_DOWN, 1, 1);
assertFalse(mController.onInterceptTouchEvent(ev));
@@ -124,7 +131,8 @@
// Add enabled gesture action
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
assertFalse(mController.onInterceptTouchEvent(ev));
verify(mNavigationBarView, times(1)).requestUnbufferedDispatch(ev);
@@ -140,7 +148,8 @@
// Add enabled gesture action
mController.setGestureActions(mockAction(true), null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
// Set the gesture on deadzone
doReturn(null).when(mProxyService).getProxy();
@@ -165,7 +174,8 @@
@Test
public void testOnTouchIgnoredDownEventAfterOnIntercept() {
mController.setGestureActions(mockAction(true), null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
MotionEvent ev = event(MotionEvent.ACTION_DOWN, 1, 1);
assertFalse(touch(ev));
@@ -178,29 +188,45 @@
@Test
public void testGesturesCallCorrectAction() throws Exception {
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
+
NavigationGestureAction swipeUp = mockAction(true);
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
+ NavigationGestureAction swipeLeftFromEdge = mockAction(true);
+ NavigationGestureAction swipeRightFromEdge = mockAction(true);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
+ swipeRightFromEdge);
// Swipe Up
assertGestureTriggersAction(swipeUp, 1, 100, 5, 1);
// Swipe Down
assertGestureTriggersAction(swipeDown, 1, 1, 5, 100);
// Swipe Left
- assertGestureTriggersAction(swipeLeft, 100, 1, 5, 1);
+ assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH / 2, 1, 5, 1);
// Swipe Right
- assertGestureTriggersAction(swipeRight, 1, 1, 100, 5);
+ assertGestureTriggersAction(swipeRight, NAVBAR_WIDTH / 2, 1, NAVBAR_WIDTH, 5);
+ // Swipe Left from Edge
+ assertGestureTriggersAction(swipeLeftFromEdge, NAVBAR_WIDTH, 1, 5, 1);
+ // Swipe Right from Edge
+ assertGestureTriggersAction(swipeRightFromEdge, 0, 1, NAVBAR_WIDTH, 5);
}
@Test
public void testGesturesCallCorrectActionLandscape() throws Exception {
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getHeight();
+
NavigationGestureAction swipeUp = mockAction(true);
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
+ NavigationGestureAction swipeLeftFromEdge = mockAction(true);
+ NavigationGestureAction swipeRightFromEdge = mockAction(true);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
+ swipeRightFromEdge);
// In landscape
mController.setBarState(false /* isRTL */, NAV_BAR_RIGHT);
@@ -208,34 +234,50 @@
// Swipe Up
assertGestureTriggersAction(swipeRight, 1, 100, 5, 1);
// Swipe Down
- assertGestureTriggersAction(swipeLeft, 1, 1, 5, 100);
+ assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, NAVBAR_WIDTH);
// Swipe Left
assertGestureTriggersAction(swipeUp, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeDown, 1, 1, 100, 5);
+ // Swipe Up from Edge
+ assertGestureTriggersAction(swipeRightFromEdge, 1, NAVBAR_WIDTH, 5, 0);
+ // Swipe Down from Edge
+ assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
public void testGesturesCallCorrectActionSeascape() throws Exception {
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getHeight();
+
mController.setBarState(false /* isRTL */, NAV_BAR_LEFT);
NavigationGestureAction swipeUp = mockAction(true);
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
+ NavigationGestureAction swipeLeftFromEdge = mockAction(true);
+ NavigationGestureAction swipeRightFromEdge = mockAction(true);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
+ swipeRightFromEdge);
// Swipe Up
- assertGestureTriggersAction(swipeLeft, 1, 100, 5, 1);
+ assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, 1);
// Swipe Down
- assertGestureTriggersAction(swipeRight, 1, 1, 5, 100);
+ assertGestureTriggersAction(swipeRight, 1, NAVBAR_WIDTH / 2, 5, NAVBAR_WIDTH);
// Swipe Left
assertGestureTriggersAction(swipeDown, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeUp, 1, 1, 100, 5);
+ // Swipe Up from Edge
+ assertGestureTriggersAction(swipeLeftFromEdge, 1, NAVBAR_WIDTH, 5, 0);
+ // Swipe Down from Edge
+ assertGestureTriggersAction(swipeRightFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
public void testGesturesCallCorrectActionRTL() throws Exception {
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
mController.setBarState(true /* isRTL */, NAV_BAR_BOTTOM);
// The swipe gestures below are for LTR, so RTL in portrait will be swapped
@@ -243,20 +285,29 @@
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
+ NavigationGestureAction swipeLeftFromEdge = mockAction(true);
+ NavigationGestureAction swipeRightFromEdge = mockAction(true);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
+ swipeRightFromEdge);
// Swipe Up in RTL
assertGestureTriggersAction(swipeUp, 1, 100, 5, 1);
// Swipe Down in RTL
assertGestureTriggersAction(swipeDown, 1, 1, 5, 100);
// Swipe Left in RTL
- assertGestureTriggersAction(swipeRight, 100, 1, 5, 1);
+ assertGestureTriggersAction(swipeRight, NAVBAR_WIDTH / 2, 1, 5, 1);
// Swipe Right in RTL
- assertGestureTriggersAction(swipeLeft, 1, 1, 100, 5);
+ assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH / 2, 1, NAVBAR_WIDTH, 0);
+ // Swipe Left from Edge
+ assertGestureTriggersAction(swipeRightFromEdge, NAVBAR_WIDTH, 1, 5, 1);
+ // Swipe Right from Edge
+ assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, NAVBAR_WIDTH, 5);
}
@Test
public void testGesturesCallCorrectActionLandscapeRTL() throws Exception {
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getHeight();
mController.setBarState(true /* isRTL */, NAV_BAR_RIGHT);
// The swipe gestures below are for LTR, so RTL in landscape will be swapped
@@ -264,20 +315,29 @@
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
+ NavigationGestureAction swipeLeftFromEdge = mockAction(true);
+ NavigationGestureAction swipeRightFromEdge = mockAction(true);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
+ swipeRightFromEdge);
// Swipe Up
- assertGestureTriggersAction(swipeLeft, 1, 100, 5, 1);
+ assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, 1);
// Swipe Down
- assertGestureTriggersAction(swipeRight, 1, 1, 5, 100);
+ assertGestureTriggersAction(swipeRight, 1, NAVBAR_WIDTH / 2, 5, NAVBAR_WIDTH);
// Swipe Left
assertGestureTriggersAction(swipeUp, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeDown, 1, 1, 100, 5);
+ // Swipe Up from Edge
+ assertGestureTriggersAction(swipeLeftFromEdge, 1, NAVBAR_WIDTH, 5, 0);
+ // Swipe Down from Edge
+ assertGestureTriggersAction(swipeRightFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
public void testGesturesCallCorrectActionSeascapeRTL() throws Exception {
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getHeight();
mController.setBarState(true /* isRTL */, NAV_BAR_LEFT);
// The swipe gestures below are for LTR, so RTL in seascape will be swapped
@@ -285,16 +345,23 @@
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
+ NavigationGestureAction swipeLeftFromEdge = mockAction(true);
+ NavigationGestureAction swipeRightFromEdge = mockAction(true);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
+ swipeRightFromEdge);
// Swipe Up
- assertGestureTriggersAction(swipeRight, 1, 100, 5, 1);
+ assertGestureTriggersAction(swipeRight, 1, NAVBAR_WIDTH / 2, 5, 1);
// Swipe Down
- assertGestureTriggersAction(swipeLeft, 1, 1, 5, 100);
+ assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, NAVBAR_WIDTH);
// Swipe Left
assertGestureTriggersAction(swipeDown, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeUp, 1, 1, 100, 5);
+ // Swipe Up from Edge
+ assertGestureTriggersAction(swipeRightFromEdge, 1, NAVBAR_WIDTH, 5, 0);
+ // Swipe Down from Edge
+ assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
@@ -305,7 +372,8 @@
// Add enabled gesture action
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
// Touch down to begin swipe
MotionEvent downEvent = event(MotionEvent.ACTION_DOWN, 1, 100);
@@ -326,7 +394,8 @@
NavigationGestureAction action = mockAction(true);
doReturn(false).when(action).canRunWhenNotificationsShowing();
mController.setGestureActions(action, null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
// Show the notifications
doReturn(false).when(mNavigationBarView).isNotificationsFullyCollapsed();
@@ -351,7 +420,8 @@
public void testActionCannotPerform() throws Exception {
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
// Cannot perform action
doReturn(false).when(action).canPerformAction();
@@ -374,13 +444,17 @@
@Test
public void testQuickScrub() throws Exception {
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
QuickScrubAction action = spy(new QuickScrubAction(mNavigationBarView, mProxyService));
mController.setGestureActions(null /* swipeUpAction */, null /* swipeDownAction */,
- null /* swipeLeftAction */, action);
+ null /* swipeLeftAction */, action, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
+ int x = NAVBAR_WIDTH / 2;
int y = 20;
// Set the layout and other padding to make sure the scrub fraction is calculated correctly
- action.onLayout(true, 0, 0, 400, 100);
+ action.onLayout(true, 0, 0, NAVBAR_WIDTH, NAVBAR_HEIGHT);
doReturn(0).when(mNavigationBarView).getPaddingLeft();
doReturn(0).when(mNavigationBarView).getPaddingRight();
doReturn(0).when(mNavigationBarView).getPaddingStart();
@@ -393,14 +467,14 @@
doReturn(true).when(mNavigationBarView).isQuickScrubEnabled();
// Touch down
- MotionEvent downEvent = event(MotionEvent.ACTION_DOWN, 0, y);
+ MotionEvent downEvent = event(MotionEvent.ACTION_DOWN, x, y);
assertFalse(touch(downEvent));
assertNull(mController.getCurrentAction());
verify(mProxy, times(1)).onPreMotionEvent(mNavigationBarView.getDownHitTarget());
verify(mProxy, times(1)).onMotionEvent(downEvent);
// Move to start trigger action from gesture
- MotionEvent moveEvent1 = event(MotionEvent.ACTION_MOVE, 100, y);
+ MotionEvent moveEvent1 = event(MotionEvent.ACTION_MOVE, x + 100, y);
assertTrue(touch(moveEvent1));
assertEquals(action, mController.getCurrentAction());
verify(action, times(1)).onGestureStart(moveEvent1);
@@ -410,11 +484,13 @@
verify(mProxy, never()).onMotionEvent(moveEvent1);
// Move again for scrub
- MotionEvent moveEvent2 = event(MotionEvent.ACTION_MOVE, 200, y);
+ float fraction = 3f / 4;
+ x = (int) (NAVBAR_WIDTH * fraction);
+ MotionEvent moveEvent2 = event(MotionEvent.ACTION_MOVE, x, y);
assertTrue(touch(moveEvent2));
assertEquals(action, mController.getCurrentAction());
- verify(action, times(1)).onGestureMove(200, y);
- verify(mProxy, times(1)).onQuickScrubProgress(1f / 2);
+ verify(action, times(1)).onGestureMove(x, y);
+ verify(mProxy, times(1)).onQuickScrubProgress(fraction);
verify(mProxy, never()).onMotionEvent(moveEvent2);
// Action up
@@ -430,7 +506,8 @@
public void testQuickStep() throws Exception {
QuickStepAction action = new QuickStepAction(mNavigationBarView, mProxyService);
mController.setGestureActions(action, null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
// Notifications are up, should prevent quickstep
doReturn(false).when(mNavigationBarView).isNotificationsFullyCollapsed();
@@ -466,7 +543,8 @@
public void testLongPressPreventDetection() throws Exception {
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
// Start the drag up
assertFalse(touch(MotionEvent.ACTION_DOWN, 100, 1));
@@ -488,23 +566,21 @@
@Test
public void testHitTargetDragged() throws Exception {
- final int navbarWidth = 1000;
- final int navbarHeight = 1000;
ButtonDispatcher button = mock(ButtonDispatcher.class);
- FakeLocationView buttonView = spy(new FakeLocationView(mContext, navbarWidth / 2,
- navbarHeight / 2));
+ FakeLocationView buttonView = spy(new FakeLocationView(mContext, NAVBAR_WIDTH / 2,
+ NAVBAR_HEIGHT / 2));
doReturn(buttonView).when(button).getCurrentView();
NavigationGestureAction action = mockAction(true);
- mController.setGestureActions(action, action, action, action);
+ mController.setGestureActions(action, action, action, action, action, action);
// Setup getting the hit target
doReturn(HIT_TARGET_HOME).when(action).requiresTouchDownHitTarget();
- doReturn(true).when(action).requiresDragWithHitTarget();
+ doReturn(true).when(action).allowHitTargetToMoveOverDrag();
doReturn(HIT_TARGET_HOME).when(mNavigationBarView).getDownHitTarget();
doReturn(button).when(mNavigationBarView).getHomeButton();
- doReturn(navbarWidth).when(mNavigationBarView).getWidth();
- doReturn(navbarHeight).when(mNavigationBarView).getHeight();
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
// Portrait
assertGestureDragsHitTargetAllDirections(buttonView, false /* isRTL */, NAV_BAR_BOTTOM);
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 89220d5..dec0c29 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6609,6 +6609,18 @@
// OS: Q
DIALOG_DISABLE_DEVELOPMENT_OPTIONS = 1591;
+ // Tag for an ACTION: QS -> Tile click / Secondary click / long press
+ // indicating the StatusBarState when menu was pulled down
+ // CATEGORY: QUICK_SETTINGS
+ // OS: Q
+ FIELD_STATUS_BAR_STATE = 1592;
+
+ // Tag for an ACTION: QS -> Tile click / Secondary click / long press
+ // indicating whether current state is full QS
+ // CATEGORY: QUICK_SETTINGS
+ // OS: Q
+ FIELD_IS_FULL_QS = 1593;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 9cfd39c..65cd329 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -55,7 +55,12 @@
// add other system settings here...
sGlobalSettingToTypeMap.put(Settings.Global.DEBUG_VIEW_ATTRIBUTES, int.class);
- sGlobalSettingToTypeMap.put(Settings.Global.ANGLE_ENABLED_APP, String.class);
+ sGlobalSettingToTypeMap.put(
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE, String.class);
+ sGlobalSettingToTypeMap.put(
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS, String.class);
+ sGlobalSettingToTypeMap.put(
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 95e1962f..f19ecf3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5511,7 +5511,12 @@
{
mHandler.removeCallbacksAndMessages(r);
Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
- long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
+ int delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
+ // Accessibility users may need longer timeout duration. This api compares original delay
+ // with user's preference and return longer one. It returns original delay if there's no
+ // preference.
+ delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
+ AccessibilityManager.FLAG_CONTENT_TEXT);
mHandler.sendMessageDelayed(m, delay);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index dca92ea..6bfcfa2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11258,7 +11258,7 @@
== UsesPermissionInfo.USAGE_UNDEFINED
|| upi.getDataRetention() == UsesPermissionInfo.RETENTION_UNDEFINED) {
// STOPSHIP: Make this throw
- Slog.wtf(TAG, "Package " + pkg.packageName + " does not provide usage "
+ Slog.e(TAG, "Package " + pkg.packageName + " does not provide usage "
+ "information for permission " + upi.getPermission()
+ ". This will be a fatal error in Q.");
}
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index da997ba..10542d5 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -48,12 +48,16 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.RootActivityContainer.FindTaskResult;
import static com.android.server.wm.RootActivityContainer.TAG_STATES;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.graphics.Point;
+import android.os.IBinder;
import android.os.UserHandle;
import android.util.IntArray;
import android.util.Slog;
@@ -86,6 +90,8 @@
private ActivityTaskManagerService mService;
private RootActivityContainer mRootActivityContainer;
+ // TODO: Remove once unification is complete.
+ DisplayContent mDisplayContent;
/** Actual Display this object tracks. */
int mDisplayId;
Display mDisplay;
@@ -138,8 +144,6 @@
// Used in updating the display size
private Point mTmpDisplaySize = new Point();
- private DisplayWindowController mWindowContainerController;
-
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
ActivityDisplay(RootActivityContainer root, Display display) {
@@ -147,19 +151,15 @@
mService = root.mService;
mDisplayId = display.getDisplayId();
mDisplay = display;
- mWindowContainerController = createWindowContainerController();
+ mDisplayContent = createDisplayContent();
updateBounds();
}
- protected DisplayWindowController createWindowContainerController() {
- return new DisplayWindowController(mDisplay, this);
+ protected DisplayContent createDisplayContent() {
+ return mService.mWindowManager.mRoot.createDisplayContent(mDisplay, this);
}
- DisplayWindowController getWindowContainerController() {
- return mWindowContainerController;
- }
-
- void updateBounds() {
+ private void updateBounds() {
mDisplay.getRealSize(mTmpDisplaySize);
setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
}
@@ -178,7 +178,10 @@
}
updateBounds();
- mWindowContainerController.onDisplayChanged();
+ if (mDisplayContent != null) {
+ mDisplayContent.updateDisplayInfo();
+ mService.mWindowManager.requestTraversal();
+ }
}
@Override
@@ -270,9 +273,9 @@
// ActivityStack#getWindowContainerController() can be null. In this special case,
// since DisplayContest#positionStackAt() is called in TaskStack#onConfigurationChanged(),
// we don't have to call WindowContainerController#positionChildAt() here.
- if (stack.getWindowContainerController() != null) {
- mWindowContainerController.positionChildAt(stack.getWindowContainerController(),
- insertPosition, includingParents);
+ if (stack.getWindowContainerController() != null && mDisplayContent != null) {
+ mDisplayContent.positionStackAt(insertPosition,
+ stack.getWindowContainerController().mContainer, includingParents);
}
if (!wasContained) {
stack.setParent(this);
@@ -958,17 +961,23 @@
getRequestedOverrideConfiguration().windowConfiguration.getRotation();
if (currRotation != ROTATION_UNDEFINED
&& currRotation != overrideConfiguration.windowConfiguration.getRotation()
- && getWindowContainerController() != null) {
- getWindowContainerController().applyRotation(currRotation,
+ && mDisplayContent != null) {
+ mDisplayContent.applyRotationLocked(currRotation,
overrideConfiguration.windowConfiguration.getRotation());
}
super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
+ if (mDisplayContent != null) {
+ mService.mWindowManager.setNewDisplayOverrideConfiguration(
+ overrideConfiguration, mDisplayContent);
+ }
}
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
// update resources before cascade so that docked/pinned stacks use the correct info
- getWindowContainerController().preOnConfigurationChanged();
+ if (mDisplayContent != null) {
+ mDisplayContent.preOnConfigurationChanged();
+ }
super.onConfigurationChanged(newParentConfig);
}
@@ -1099,8 +1108,8 @@
private void releaseSelfIfNeeded() {
if (mStacks.isEmpty() && mRemoved) {
- mWindowContainerController.removeContainer();
- mWindowContainerController = null;
+ mDisplayContent.removeIfPossible();
+ mDisplayContent = null;
mRootActivityContainer.removeChild(this);
mRootActivityContainer.mStackSupervisor
.getKeyguardController().onDisplayRemoved(mDisplayId);
@@ -1122,7 +1131,7 @@
* @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
*/
boolean supportsSystemDecorations() {
- return mWindowContainerController.supportsSystemDecorations();
+ return mDisplayContent.supportsSystemDecorations();
}
@VisibleForTesting
@@ -1136,7 +1145,30 @@
}
void setFocusedApp(ActivityRecord r, boolean moveFocusNow) {
- mWindowContainerController.setFocusedApp(r.appToken, moveFocusNow);
+ if (mDisplayContent == null) {
+ return;
+ }
+ final AppWindowToken newFocus;
+ final IBinder token = r.appToken;
+ if (token == null) {
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Clearing focused app, displayId="
+ + mDisplayId);
+ newFocus = null;
+ } else {
+ newFocus = mService.mWindowManager.mRoot.getAppWindowToken(token);
+ if (newFocus == null) {
+ Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
+ + ", displayId=" + mDisplayId);
+ }
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Set focused app to: " + newFocus
+ + " moveFocusNow=" + moveFocusNow + " displayId=" + mDisplayId);
+ }
+
+ final boolean changed = mDisplayContent.setFocusedApp(newFocus);
+ if (moveFocusNow && changed) {
+ mService.mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+ true /*updateInputWindows*/);
+ }
}
/**
@@ -1284,17 +1316,21 @@
}
/**
- * See {@link DisplayWindowController#deferUpdateImeTarget()}
+ * See {@link DisplayContent#deferUpdateImeTarget()}
*/
public void deferUpdateImeTarget() {
- mWindowContainerController.deferUpdateImeTarget();
+ if (mDisplayContent != null) {
+ mDisplayContent.deferUpdateImeTarget();
+ }
}
/**
- * See {@link DisplayWindowController#deferUpdateImeTarget()}
+ * See {@link DisplayContent#deferUpdateImeTarget()}
*/
public void continueUpdateImeTarget() {
- mWindowContainerController.continueUpdateImeTarget();
+ if (mDisplayContent != null) {
+ mDisplayContent.continueUpdateImeTarget();
+ }
}
public void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 26a4cef..4e9c5ab 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2942,7 +2942,7 @@
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(
- getDisplay().getWindowContainerController().isNextTransitionForward());
+ getDisplay().mDisplayContent.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index c41a173..7683172 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -574,7 +574,7 @@
// bounds were on the pre-rotated display.
if (prevRotation != newRotation) {
mTmpRect2.set(mTmpRect);
- getDisplay().getWindowContainerController().mContainer
+ getDisplay().mDisplayContent
.rotateBounds(newParentConfig.windowConfiguration.getBounds(),
prevRotation, newRotation, mTmpRect2);
hasNewOverrideBounds = true;
@@ -609,8 +609,8 @@
} else if (
getRequestedOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
Rect dockedBounds = display.getSplitScreenPrimaryStack().getBounds();
- final boolean isMinimizedDock = getDisplay().getWindowContainerController()
- .mContainer.getDockedDividerController().isMinimizedDock();
+ final boolean isMinimizedDock =
+ getDisplay().mDisplayContent.getDockedDividerController().isMinimizedDock();
if (isMinimizedDock) {
TaskRecord topTask = display.getSplitScreenPrimaryStack().topTask();
if (topTask != null) {
@@ -2714,16 +2714,16 @@
// that the previous one will be hidden soon. This way it can know
// to ignore it when computing the desired screen orientation.
boolean anim = true;
- final DisplayWindowController dwc = getDisplay().getWindowContainerController();
+ final DisplayContent dc = getDisplay().mDisplayContent;
if (prev != null) {
if (prev.finishing) {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare close transition: prev=" + prev);
if (mStackSupervisor.mNoAnimActivities.contains(prev)) {
anim = false;
- dwc.prepareAppTransition(TRANSIT_NONE, false);
+ dc.prepareAppTransition(TRANSIT_NONE, false);
} else {
- dwc.prepareAppTransition(
+ dc.prepareAppTransition(
prev.getTaskRecord() == next.getTaskRecord() ? TRANSIT_ACTIVITY_CLOSE
: TRANSIT_TASK_CLOSE, false);
}
@@ -2733,9 +2733,9 @@
"Prepare open transition: prev=" + prev);
if (mStackSupervisor.mNoAnimActivities.contains(next)) {
anim = false;
- dwc.prepareAppTransition(TRANSIT_NONE, false);
+ dc.prepareAppTransition(TRANSIT_NONE, false);
} else {
- dwc.prepareAppTransition(
+ dc.prepareAppTransition(
prev.getTaskRecord() == next.getTaskRecord() ? TRANSIT_ACTIVITY_OPEN
: next.mLaunchTaskBehind ? TRANSIT_TASK_OPEN_BEHIND
: TRANSIT_TASK_OPEN, false);
@@ -2745,9 +2745,9 @@
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
if (mStackSupervisor.mNoAnimActivities.contains(next)) {
anim = false;
- dwc.prepareAppTransition(TRANSIT_NONE, false);
+ dc.prepareAppTransition(TRANSIT_NONE, false);
} else {
- dwc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false);
+ dc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false);
}
}
@@ -2869,8 +2869,7 @@
next.clearOptionsLocked();
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.getReportedProcState(),
- getDisplay().getWindowContainerController()
- .isNextTransitionForward()));
+ getDisplay().mDisplayContent.isNextTransitionForward()));
mService.getLifecycleManager().scheduleTransaction(transaction);
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
@@ -3072,11 +3071,11 @@
task.setFrontOfTask();
if (!isHomeOrRecentsStack() || numActivities() > 0) {
- final DisplayWindowController dwc = getDisplay().getWindowContainerController();
+ final DisplayContent dc = getDisplay().mDisplayContent;
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
- dwc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
+ dc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
mStackSupervisor.mNoAnimActivities.add(r);
} else {
int transit = TRANSIT_ACTIVITY_OPEN;
@@ -3095,7 +3094,7 @@
transit = TRANSIT_TASK_OPEN;
}
}
- dwc.prepareAppTransition(transit, keepCurTransition);
+ dc.prepareAppTransition(transit, keepCurTransition);
mStackSupervisor.mNoAnimActivities.remove(r);
}
boolean doShow = true;
@@ -3724,7 +3723,7 @@
int taskNdx = mTaskHistory.indexOf(finishedTask);
final TaskRecord task = finishedTask;
int activityNdx = task.mActivities.indexOf(r);
- getDisplay().getWindowContainerController().prepareAppTransition(
+ getDisplay().mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
finishedTask = task;
@@ -3890,7 +3889,7 @@
mService.getTaskChangeNotificationController().notifyTaskRemovalStarted(
task.taskId);
}
- getDisplay().getWindowContainerController().prepareAppTransition(transit, false);
+ getDisplay().mDisplayContent.prepareAppTransition(transit, false);
// Tell window manager to prepare for this one to be removed.
r.setVisibility(false);
@@ -3945,10 +3944,10 @@
}
private void prepareActivityHideTransitionAnimation(ActivityRecord r, int transit) {
- final DisplayWindowController dwc = getDisplay().getWindowContainerController();
- dwc.prepareAppTransition(transit, false);
+ final DisplayContent dc = getDisplay().mDisplayContent;
+ dc.prepareAppTransition(transit, false);
r.setVisibility(false);
- dwc.executeAppTransition();
+ dc.executeAppTransition();
if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(r)) {
mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(r);
}
@@ -4692,7 +4691,7 @@
ActivityOptions.abort(options);
}
}
- getDisplay().getWindowContainerController().prepareAppTransition(transit, false);
+ getDisplay().mDisplayContent.prepareAppTransition(transit, false);
}
private void updateTaskMovement(TaskRecord task, boolean toFront) {
@@ -4761,8 +4760,7 @@
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
if (noAnimation) {
- getDisplay().getWindowContainerController().prepareAppTransition(
- TRANSIT_NONE, false);
+ getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_NONE, false);
if (r != null) {
mStackSupervisor.mNoAnimActivities.add(r);
}
@@ -4844,8 +4842,7 @@
mTaskHistory.add(0, tr);
updateTaskMovement(tr, false);
- getDisplay().getWindowContainerController().prepareAppTransition(
- TRANSIT_TASK_TO_BACK, false);
+ getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
moveToBack("moveTaskToBackLocked", tr);
if (inPinnedWindowingMode()) {
@@ -5170,7 +5167,7 @@
+ r.intent.getComponent().flattenToShortString());
// Force the destroy to skip right to removal.
r.app = null;
- getDisplay().getWindowContainerController().prepareAppTransition(
+ getDisplay().mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
"handleAppCrashedLocked");
@@ -5508,7 +5505,7 @@
}
void executeAppTransition(ActivityOptions options) {
- getDisplay().getWindowContainerController().executeAppTransition();
+ getDisplay().mDisplayContent.executeAppTransition();
ActivityOptions.abort(options);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index d92a9f2..e761ad8 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -818,7 +818,7 @@
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
- final DisplayWindowController dwc = r.getDisplay().getWindowContainerController();
+ final DisplayContent dc = r.getDisplay().mDisplayContent;
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
@@ -827,12 +827,12 @@
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.icicle, r.persistentState, results, newIntents,
- dwc.isNextTransitionForward(), profilerInfo));
+ dc.isNextTransitionForward(), profilerInfo));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
- lifecycleItem = ResumeActivityItem.obtain(dwc.isNextTransitionForward());
+ lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index bc2136e..4538d36 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1565,7 +1565,7 @@
mTargetStack.ensureActivitiesVisibleLocked(null, 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().getWindowContainerController().executeAppTransition();
+ mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0301a5b..182d1a0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1738,7 +1738,7 @@
if (self.isState(
ActivityStack.ActivityState.RESUMED, ActivityStack.ActivityState.PAUSING)) {
- self.getDisplay().getWindowContainerController().overridePendingAppTransition(
+ self.getDisplay().mDisplayContent.mAppTransition.overridePendingAppTransition(
packageName, enterAnim, exitAnim, null);
}
@@ -3073,12 +3073,11 @@
// Get top display of front most application.
final ActivityStack focusedStack = getTopDisplayFocusedStack();
if (focusedStack != null) {
- final DisplayWindowController dwc =
- focusedStack.getDisplay().getWindowContainerController();
- dwc.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
- dwc.overridePendingAppTransitionInPlace(activityOptions.getPackageName(),
+ final DisplayContent dc = focusedStack.getDisplay().mDisplayContent;
+ dc.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
+ dc.mAppTransition.overrideInPlaceAppTransition(activityOptions.getPackageName(),
activityOptions.getCustomInPlaceResId());
- dwc.executeAppTransition();
+ dc.executeAppTransition();
}
}
@@ -5770,17 +5769,18 @@
if (activityDisplay == null) {
return;
}
- final DisplayWindowController dwc = activityDisplay.getWindowContainerController();
- final boolean wasTransitionSet = dwc.getPendingAppTransition() != TRANSIT_NONE;
+ final DisplayContent dc = activityDisplay.mDisplayContent;
+ final boolean wasTransitionSet =
+ dc.mAppTransition.getAppTransition() != TRANSIT_NONE;
if (!wasTransitionSet) {
- dwc.prepareAppTransition(TRANSIT_NONE, false /* alwaysKeepCurrent */);
+ dc.prepareAppTransition(TRANSIT_NONE, false /* alwaysKeepCurrent */);
}
mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
// If there was a transition set already we don't want to interfere with it as we
// might be starting it too early.
if (!wasTransitionSet) {
- dwc.executeAppTransition();
+ dc.executeAppTransition();
}
}
if (callback != null) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index aba2eb3..2f4c5ca 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -59,8 +59,11 @@
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
+import static android.view.WindowManager.TRANSIT_TASK_OPEN;
+import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
@@ -207,6 +210,9 @@
/** Unique identifier of this stack. */
private final int mDisplayId;
+ // TODO: Remove once unification is complete.
+ ActivityDisplay mAcitvityDisplay;
+
/** The containers below are the only child containers the display can have. */
// Contains all window containers that are related to apps (Activities)
private final TaskStackContainers mTaskStackContainers = new TaskStackContainers(mWmService);
@@ -227,7 +233,6 @@
private WindowState mTmpWindow;
private WindowState mTmpWindow2;
- private WindowAnimator mTmpWindowAnimator;
private boolean mTmpRecoveringMemory;
private boolean mUpdateImeTarget;
private boolean mTmpInitial;
@@ -827,12 +832,12 @@
* initialize direct children.
* @param display May not be null.
* @param service You know.
- * @param controller The controller for the display container.
+ * @param activityDisplay The ActivityDisplay for the display container.
*/
DisplayContent(Display display, WindowManagerService service,
- DisplayWindowController controller) {
+ ActivityDisplay activityDisplay) {
super(service);
- setController(controller);
+ mAcitvityDisplay = activityDisplay;
if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
+ " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
@@ -1020,11 +1025,6 @@
}
@Override
- DisplayWindowController getController() {
- return (DisplayWindowController) super.getController();
- }
-
- @Override
public Display getDisplay() {
return mDisplay;
}
@@ -1138,6 +1138,17 @@
return true;
}
+ /**
+ * The display content may have configuration set from {@link #DisplayWindowSettings}. This
+ * callback let the owner of container know there is existing configuration to prevent the
+ * values from being replaced by the initializing {@link #ActivityDisplay}.
+ */
+ void initializeDisplayOverrideConfiguration() {
+ if (mAcitvityDisplay != null) {
+ mAcitvityDisplay.onInitializeOverrideConfiguration(getRequestedOverrideConfiguration());
+ }
+ }
+
/** Notify the configuration change of this display. */
void sendNewConfiguration() {
mWmService.mH.obtainMessage(SEND_NEW_CONFIGURATION, this).sendToTarget();
@@ -4686,6 +4697,11 @@
}
void prepareAppTransition(@WindowManager.TransitionType int transit,
+ boolean alwaysKeepCurrent) {
+ prepareAppTransition(transit, alwaysKeepCurrent, 0 /* flags */, false /* forceOverride */);
+ }
+
+ void prepareAppTransition(@WindowManager.TransitionType int transit,
boolean alwaysKeepCurrent, @WindowManager.TransitionFlags int flags,
boolean forceOverride) {
final boolean prepared = mAppTransition.prepareAppTransitionLocked(
@@ -4737,6 +4753,14 @@
pendingLayoutChanges |= changes;
}
+ /** Check if pending app transition is for activity / task launch. */
+ boolean isNextTransitionForward() {
+ final int transit = mAppTransition.getAppTransition();
+ return transit == TRANSIT_ACTIVITY_OPEN
+ || transit == TRANSIT_TASK_OPEN
+ || transit == TRANSIT_TASK_TO_FRONT;
+ }
+
/**
* @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
*/
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index d4bd91b..8b8cadc 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -763,6 +763,12 @@
|| attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
}
+ // Accessibility users may need longer timeout duration. This api compares
+ // original timeout with user's preference and return longer one. It returns
+ // original timeout if there's no preference.
+ attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
+ (int) attrs.hideTimeoutMilliseconds,
+ AccessibilityManager.FLAG_CONTENT_TEXT);
attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
break;
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
deleted file mode 100644
index c7eadf9..0000000
--- a/services/core/java/com/android/server/wm/DisplayWindowController.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_TASK_OPEN;
-import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
-
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
-
-import android.content.res.Configuration;
-import android.graphics.GraphicBuffer;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.IRemoteCallback;
-import android.util.Slog;
-import android.view.AppTransitionAnimationSpec;
-import android.view.Display;
-import android.view.WindowManager;
-import android.view.WindowManager.TransitionType;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Controller for the display container. This is created by activity manager to link activity
- * displays to the display content they use in window manager.
- */
-public class DisplayWindowController
- extends WindowContainerController<DisplayContent, WindowContainerListener> {
-
- private final int mDisplayId;
-
- public DisplayWindowController(Display display, WindowContainerListener listener) {
- super(listener, WindowManagerService.getInstance());
- mDisplayId = display.getDisplayId();
-
- synchronized (mGlobalLock) {
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- mRoot.createDisplayContent(display, this /* controller */);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
-
- if (mContainer == null) {
- throw new IllegalArgumentException("Trying to add display=" + display
- + " dc=" + mRoot.getDisplayContent(mDisplayId));
- }
- }
- }
-
- @VisibleForTesting
- public DisplayWindowController(Display display, WindowManagerService service) {
- super(null, service);
- mDisplayId = display.getDisplayId();
- }
-
- @Override
- public void removeContainer() {
- synchronized (mGlobalLock) {
- if(mContainer == null) {
- if (DEBUG_DISPLAY) Slog.i(TAG_WM, "removeDisplay: could not find displayId="
- + mDisplayId);
- return;
- }
- mContainer.removeIfPossible();
- super.removeContainer();
- }
- }
-
- @Override
- public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
- synchronized (mGlobalLock) {
- if (mContainer != null) {
- mContainer.mWmService.setNewDisplayOverrideConfiguration(overrideConfiguration,
- mContainer);
- }
- }
- }
-
- /**
- * Updates the docked/pinned controller resources to the current system context.
- */
- public void preOnConfigurationChanged() {
- synchronized (mGlobalLock) {
- if (mContainer != null) {
- mContainer.preOnConfigurationChanged();
- }
- }
- }
-
- /**
- * @see DisplayContent#applyRotationLocked(int, int)
- */
- public void applyRotation(int oldRotation, int newRotation) {
- synchronized (mGlobalLock) {
- if (mContainer != null) {
- mContainer.applyRotationLocked(oldRotation, newRotation);
- }
- }
- }
-
- public int getDisplayId() {
- return mDisplayId;
- }
-
- /**
- * Called when the corresponding display receives
- * {@link android.hardware.display.DisplayManager.DisplayListener#onDisplayChanged(int)}.
- */
- public void onDisplayChanged() {
- synchronized (mGlobalLock) {
- if (mContainer == null) {
- if (DEBUG_DISPLAY) Slog.i(TAG_WM, "onDisplayChanged: could not find display="
- + mDisplayId);
- return;
- }
- mContainer.updateDisplayInfo();
- mService.mWindowPlacerLocked.requestTraversal();
- }
- }
-
- /**
- * Positions the task stack at the given position in the task stack container.
- */
- public void positionChildAt(StackWindowController child, int position,
- boolean includingParents) {
- synchronized (mGlobalLock) {
- if (DEBUG_STACK) Slog.i(TAG_WM, "positionTaskStackAt: positioning stack=" + child
- + " at " + position);
- if (mContainer == null) {
- if (DEBUG_STACK) Slog.i(TAG_WM,
- "positionTaskStackAt: could not find display=" + mContainer);
- return;
- }
- if (child.mContainer == null) {
- if (DEBUG_STACK) Slog.i(TAG_WM,
- "positionTaskStackAt: could not find stack=" + this);
- return;
- }
- mContainer.positionStackAt(position, child.mContainer, includingParents);
- }
- }
-
- /**
- * Starts deferring the ability to update the IME target. This is needed when a call will
- * attempt to update the IME target before all information about the Windows have been updated.
- */
- public void deferUpdateImeTarget() {
- synchronized (mGlobalLock) {
- final DisplayContent dc = mRoot.getDisplayContent(mDisplayId);
- if (dc != null) {
- dc.deferUpdateImeTarget();
- }
- }
- }
-
- /**
- * Resumes updating the IME target after deferring. See {@link #deferUpdateImeTarget()}
- */
- public void continueUpdateImeTarget() {
- synchronized (mGlobalLock) {
- final DisplayContent dc = mRoot.getDisplayContent(mDisplayId);
- if (dc != null) {
- dc.continueUpdateImeTarget();
- }
- }
- }
-
- /**
- * Sets a focused app on this display.
- *
- * @param token Specifies which app should be focused.
- * @param moveFocusNow Specifies if we should update the focused window immediately.
- */
- public void setFocusedApp(IBinder token, boolean moveFocusNow) {
- synchronized (mGlobalLock) {
- if (mContainer == null) {
- if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "setFocusedApp: could not find displayId="
- + mDisplayId);
- return;
- }
- final AppWindowToken newFocus;
- if (token == null) {
- if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Clearing focused app, displayId="
- + mDisplayId);
- newFocus = null;
- } else {
- newFocus = mRoot.getAppWindowToken(token);
- if (newFocus == null) {
- Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
- + ", displayId=" + mDisplayId);
- }
- if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Set focused app to: " + newFocus
- + " moveFocusNow=" + moveFocusNow + " displayId=" + mDisplayId);
- }
-
- final boolean changed = mContainer.setFocusedApp(newFocus);
- if (moveFocusNow && changed) {
- mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
- true /*updateInputWindows*/);
- }
- }
- }
-
- public void prepareAppTransition(@WindowManager.TransitionType int transit,
- boolean alwaysKeepCurrent) {
- prepareAppTransition(transit, alwaysKeepCurrent, 0 /* flags */, false /* forceOverride */);
- }
-
- /**
- * @param transit What kind of transition is happening. Use one of the constants
- * AppTransition.TRANSIT_*.
- * @param alwaysKeepCurrent If true and a transition is already set, new transition will NOT
- * be set.
- * @param flags Additional flags for the app transition, Use a combination of the constants
- * AppTransition.TRANSIT_FLAG_*.
- * @param forceOverride Always override the transit, not matter what was set previously.
- */
- public void prepareAppTransition(@WindowManager.TransitionType int transit,
- boolean alwaysKeepCurrent, @WindowManager.TransitionFlags int flags,
- boolean forceOverride) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId).prepareAppTransition(transit, alwaysKeepCurrent,
- flags, forceOverride);
- }
- }
-
- public void executeAppTransition() {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId).executeAppTransition();
- }
- }
-
- public void overridePendingAppTransition(String packageName,
- int enterAnim, int exitAnim, IRemoteCallback startedCallback) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId).mAppTransition.overridePendingAppTransition(
- packageName, enterAnim, exitAnim, startedCallback);
- }
- }
-
- public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
- int startHeight) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId).mAppTransition.overridePendingAppTransitionScaleUp(
- startX, startY, startWidth, startHeight);
- }
- }
-
- public void overridePendingAppTransitionClipReveal(int startX, int startY,
- int startWidth, int startHeight) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.overridePendingAppTransitionClipReveal(startX, startY,
- startWidth, startHeight);
- }
- }
-
- public void overridePendingAppTransitionThumb(GraphicBuffer srcThumb, int startX,
- int startY, IRemoteCallback startedCallback, boolean scaleUp) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.overridePendingAppTransitionThumb(srcThumb, startX, startY,
- startedCallback, scaleUp);
- }
- }
-
- public void overridePendingAppTransitionAspectScaledThumb(GraphicBuffer srcThumb, int startX,
- int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback,
- boolean scaleUp) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.overridePendingAppTransitionAspectScaledThumb(srcThumb, startX,
- startY, targetWidth, targetHeight, startedCallback, scaleUp);
- }
- }
-
- public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
- IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
- boolean scaleUp) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.overridePendingAppTransitionMultiThumb(specs,
- onAnimationStartedCallback, onAnimationFinishedCallback, scaleUp);
- }
- }
-
- public void overridePendingAppTransitionStartCrossProfileApps() {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.overridePendingAppTransitionStartCrossProfileApps();
- }
- }
-
- public void overridePendingAppTransitionInPlace(String packageName, int anim) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.overrideInPlaceAppTransition(packageName, anim);
- }
- }
-
- /**
- * Get Pending App transition of display.
- *
- * @return The pending app transition of the display.
- */
- public @TransitionType int getPendingAppTransition() {
- synchronized (mGlobalLock) {
- return mRoot.getDisplayContent(mDisplayId).mAppTransition.getAppTransition();
- }
- }
-
- /**
- * Check if pending app transition is for activity / task launch.
- */
- public boolean isNextTransitionForward() {
- final int transit = getPendingAppTransition();
- return transit == TRANSIT_ACTIVITY_OPEN
- || transit == TRANSIT_TASK_OPEN
- || transit == TRANSIT_TASK_TO_FRONT;
- }
-
- /**
- * Checks if system decorations should be shown on this display.
- *
- * @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
- */
- public boolean supportsSystemDecorations() {
- synchronized (mGlobalLock) {
- return mContainer.supportsSystemDecorations();
- }
- }
-
- @Override
- public String toString() {
- return "{DisplayWindowController displayId=" + mDisplayId + "}";
- }
-}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 4ef3513..5f56fe5 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -174,7 +174,7 @@
mWindowManager.deferSurfaceLayout();
try {
setKeyguardGoingAway(true);
- mRootActivityContainer.getDefaultDisplay().getWindowContainerController()
+ mRootActivityContainer.getDefaultDisplay().mDisplayContent
.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
false /* alwaysKeepCurrent */, convertTransitFlags(flags),
false /* forceOverride */);
@@ -302,7 +302,7 @@
if (isKeyguardLocked()) {
mWindowManager.deferSurfaceLayout();
try {
- mRootActivityContainer.getDefaultDisplay().getWindowContainerController()
+ mRootActivityContainer.getDefaultDisplay().mDisplayContent
.prepareAppTransition(resolveOccludeTransit(),
false /* alwaysKeepCurrent */, 0 /* flags */,
true /* forceOverride */);
@@ -332,11 +332,11 @@
// If we are about to unocclude the Keyguard, but we can dismiss it without security,
// we immediately dismiss the Keyguard so the activity gets shown without a flicker.
- final DisplayWindowController dwc =
- mRootActivityContainer.getDefaultDisplay().getWindowContainerController();
+ final DisplayContent dc =
+ mRootActivityContainer.getDefaultDisplay().mDisplayContent;
if (mKeyguardShowing && canDismissKeyguard()
- && dwc.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
- dwc.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */,
+ && dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
+ dc.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */,
0 /* flags */, true /* forceOverride */);
mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
@@ -355,10 +355,10 @@
}
private int resolveOccludeTransit() {
- final DisplayWindowController dwc =
- mRootActivityContainer.getDefaultDisplay().getWindowContainerController();
+ final DisplayContent dc =
+ mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
if (mBeforeUnoccludeTransit != TRANSIT_UNSET
- && dwc.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
+ && dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
// TODO(b/113840485): Handle app transition for individual display.
&& isDisplayOccluded(DEFAULT_DISPLAY)) {
@@ -369,7 +369,7 @@
} else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {
// Save transit in case we dismiss/occlude Keyguard shortly after.
- mBeforeUnoccludeTransit = dwc.getPendingAppTransition();
+ mBeforeUnoccludeTransit = dc.mAppTransition.getAppTransition();
return TRANSIT_KEYGUARD_UNOCCLUDE;
} else {
return TRANSIT_KEYGUARD_OCCLUDE;
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index d2f2863..3b66f7d 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -582,7 +582,7 @@
mSupervisor.mRootActivityContainer.resumeFocusedStacksTopActivities();
final ActivityStack stack = task.getStack();
if (stack != null) {
- stack.getDisplay().getWindowContainerController().executeAppTransition();
+ stack.getDisplay().mDisplayContent.executeAppTransition();
}
} else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 9422182..86fcf64 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -93,12 +93,12 @@
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity");
// TODO(multi-display) currently only support recents animation in default display.
- final DisplayWindowController dwc =
- mService.mRootActivityContainer.getDefaultDisplay().getWindowContainerController();
+ final DisplayContent dc =
+ mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
if (!mWindowManager.canStartRecentsAnimation()) {
notifyAnimationCancelBeforeStart(recentsAnimationRunner);
if (DEBUG) Slog.d(TAG, "Can't start recents animation, nextAppTransition="
- + dwc.getPendingAppTransition());
+ + dc.mAppTransition.getAppTransition());
return;
}
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index f7877c0..c5b42f9 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -914,7 +914,7 @@
void executeAppTransitionForAllDisplay() {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- display.getWindowContainerController().executeAppTransition();
+ display.mDisplayContent.executeAppTransition();
}
}
@@ -1254,9 +1254,8 @@
}
// TODO: remove after object merge with RootWindowContainer
- void onChildPositionChanged(DisplayWindowController childController, int position) {
+ void onChildPositionChanged(ActivityDisplay display, int position) {
// Assume AM lock is held from positionChildAt of controller in each hierarchy.
- final ActivityDisplay display = getActivityDisplay(childController.getDisplayId());
if (display != null) {
positionChildAt(display, position);
}
@@ -1281,8 +1280,7 @@
@VisibleForTesting
void addChild(ActivityDisplay activityDisplay, int position) {
positionChildAt(activityDisplay, position);
- mRootWindowContainer.positionChildAt(position,
- activityDisplay.getWindowContainerController().mContainer);
+ mRootWindowContainer.positionChildAt(position, activityDisplay.mDisplayContent);
}
void removeChild(ActivityDisplay activityDisplay) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 3a5c578..3bbef92 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -224,7 +224,7 @@
return null;
}
- DisplayContent createDisplayContent(final Display display, DisplayWindowController controller) {
+ DisplayContent createDisplayContent(final Display display, ActivityDisplay activityDisplay) {
final int displayId = display.getDisplayId();
// In select scenarios, it is possible that a DisplayContent will be created on demand
@@ -233,17 +233,17 @@
final DisplayContent existing = getDisplayContent(displayId);
if (existing != null) {
- initializeDisplayOverrideConfiguration(controller, existing);
- existing.setController(controller);
+ existing.mAcitvityDisplay = activityDisplay;
+ existing.initializeDisplayOverrideConfiguration();
return existing;
}
- final DisplayContent dc = new DisplayContent(display, mWmService, controller);
+ final DisplayContent dc = new DisplayContent(display, mWmService, activityDisplay);
if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(dc);
- initializeDisplayOverrideConfiguration(controller, dc);
+ dc.initializeDisplayOverrideConfiguration();
if (mWmService.mDisplayManagerInternal != null) {
mWmService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
@@ -256,19 +256,6 @@
return dc;
}
- /**
- * The display content may have configuration set from {@link #DisplayWindowSettings}. This
- * callback let the owner of container know there is existing configuration to prevent the
- * values from being replaced by the initializing {@link #ActivityDisplay}.
- */
- private void initializeDisplayOverrideConfiguration(DisplayWindowController controller,
- DisplayContent displayContent) {
- if (controller != null && controller.mListener != null) {
- controller.mListener.onInitializeOverrideConfiguration(
- displayContent.getRequestedOverrideConfiguration());
- }
- }
-
boolean isLayoutNeeded() {
final int numDisplays = mChildren.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
@@ -1040,7 +1027,7 @@
void positionChildAt(int position, DisplayContent child, boolean includingParents) {
super.positionChildAt(position, child, includingParents);
if (mRootActivityContainer != null) {
- mRootActivityContainer.onChildPositionChanged(child.getController(), position);
+ mRootActivityContainer.onChildPositionChanged(child.mAcitvityDisplay, position);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 65d3245..c44f306 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -81,7 +81,8 @@
}
@Override
- public void setGlobalPrivateDns(ComponentName who, int mode, String privateDnsHost) {
+ public int setGlobalPrivateDns(ComponentName who, int mode, String privateDnsHost) {
+ return DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
}
@Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index bca3b1f..041d5d8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -59,6 +59,8 @@
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_UNKNOWN;
+import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
+import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_SUCCESS;
import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
@@ -13280,32 +13282,40 @@
}
@Override
- public void setGlobalPrivateDns(@NonNull ComponentName who, int mode, String privateDnsHost) {
+ public int setGlobalPrivateDns(@NonNull ComponentName who, int mode, String privateDnsHost) {
if (!mHasFeature) {
- return;
+ return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
}
Preconditions.checkNotNull(who, "ComponentName is null");
enforceDeviceOwner(who);
+ final int returnCode;
+
switch (mode) {
case PRIVATE_DNS_MODE_OPPORTUNISTIC:
if (!TextUtils.isEmpty(privateDnsHost)) {
- throw new IllegalArgumentException("A DNS host should not be provided when " +
- "setting opportunistic mode.");
+ throw new IllegalArgumentException(
+ "Host provided for opportunistic mode, but is not needed.");
}
putPrivateDnsSettings(ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC, null);
- break;
+ return PRIVATE_DNS_SET_SUCCESS;
case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
- if (!NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
+ if (TextUtils.isEmpty(privateDnsHost)
+ || !NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
throw new IllegalArgumentException(
- String.format("Provided hostname is not valid: %s", privateDnsHost));
+ String.format("Provided hostname %s is not valid", privateDnsHost));
}
- putPrivateDnsSettings(ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
+
+ // Connectivity check will have been performed in the DevicePolicyManager before
+ // the call here.
+ putPrivateDnsSettings(
+ ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
privateDnsHost);
- break;
+ return PRIVATE_DNS_SET_SUCCESS;
default:
- throw new IllegalArgumentException(String.format("Unsupported mode: %d", mode));
+ throw new IllegalArgumentException(
+ String.format("Provided mode, %d, is not a valid mode.", mode));
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 3a56419..f553c35 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -408,6 +408,7 @@
initialize(intentFirewall, intentController, looper);
initRootActivityContainerMocks(wm);
setWindowManager(wm);
+ createDefaultDisplay();
}
void initRootActivityContainerMocks(WindowManagerService wm) {
@@ -424,7 +425,9 @@
// Called when moving activity to pinned stack.
doNothing().when(mRootActivityContainer).ensureActivitiesVisible(any(), anyInt(),
anyBoolean());
+ }
+ void createDefaultDisplay() {
// Create a default display and put a home stack on it so that we'll always have
// something focusable.
mDefaultDisplay = TestActivityDisplay.create(mStackSupervisor, DEFAULT_DISPLAY);
@@ -598,10 +601,8 @@
}
@Override
- protected DisplayWindowController createWindowContainerController() {
- DisplayWindowController out = mock(DisplayWindowController.class);
- out.mContainer = WindowTestUtils.createTestDisplayContent();
- return out;
+ protected DisplayContent createDisplayContent() {
+ return WindowTestUtils.createTestDisplayContent();
}
void removeAllTasks() {
@@ -616,6 +617,7 @@
private static WindowManagerService prepareMockWindowManager() {
final WindowManagerService service = mock(WindowManagerService.class);
+ service.mRoot = mock(RootWindowContainer.class);
doAnswer((InvocationOnMock invocationOnMock) -> {
final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 577859c..fa42289 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -80,7 +80,7 @@
@Test
public void testForceOverride() {
mWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
- mDc.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
+ mDc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
assertEquals(TRANSIT_ACTIVITY_OPEN, mDc.mAppTransition.getAppTransition());
}
@@ -102,8 +102,8 @@
@Test
public void testAppTransitionStateForMultiDisplay() {
// Create 2 displays & presume both display the state is ON for ready to display & animate.
- final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON);
- final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON);
+ final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
+ final DisplayContent dc2 = createNewDisplay(Display.STATE_ON);
// Create 2 app window tokens to represent 2 activity window.
final WindowTestUtils.TestAppWindowToken token1 = createTestAppWindowToken(dc1,
@@ -117,10 +117,10 @@
// Simulate activity resume / finish flows to prepare app transition & set visibility,
// make sure transition is set as expected for each display.
- dc1.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
+ dc1.prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
assertEquals(TRANSIT_ACTIVITY_OPEN, dc1.mAppTransition.getAppTransition());
- dc2.getController().prepareAppTransition(TRANSIT_ACTIVITY_CLOSE,
+ dc2.prepareAppTransition(TRANSIT_ACTIVITY_CLOSE,
false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
assertEquals(TRANSIT_ACTIVITY_CLOSE, dc2.mAppTransition.getAppTransition());
// One activity window is visible for resuming & the other activity window is invisible
@@ -138,8 +138,8 @@
@Test
public void testCleanAppTransitionWhenTaskStackReparent() {
// Create 2 displays & presume both display the state is ON for ready to display & animate.
- final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON);
- final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON);
+ final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
+ final DisplayContent dc2 = createNewDisplay(Display.STATE_ON);
final TaskStack stack1 = createTaskStackOnDisplay(dc1);
final Task task1 = createTaskInStack(stack1, 0 /* userId */);
@@ -151,7 +151,7 @@
dc1.mClosingApps.add(token1);
assertTrue(dc1.mClosingApps.size() > 0);
- dc1.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
+ dc1.prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
assertEquals(TRANSIT_ACTIVITY_OPEN, dc1.mAppTransition.getAppTransition());
assertTrue(dc1.mAppTransition.isTransitionSet());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 3c7b4b1..3e025f6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -875,8 +875,8 @@
}
@Override
- void initRootActivityContainerMocks(WindowManagerService wm) {
- super.initRootActivityContainerMocks(wm);
+ void createDefaultDisplay() {
+ super.createDefaultDisplay();
mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
mOtherDisplay = TestActivityDisplay.create(mTestStackSupervisor, DEFAULT_DISPLAY + 1);
mRootActivityContainer.addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP);
diff --git a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 612f9ad..8854ede 100644
--- a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -49,7 +49,7 @@
mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token);
// Make sure our handler processed the message.
- SystemClock.sleep(100);
+ mWm.mH.runWithScissors(() -> { }, 0);
assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
}
@@ -65,7 +65,7 @@
mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token2);
// Make sure our handler processed the message.
- SystemClock.sleep(100);
+ mWm.mH.runWithScissors(() -> { }, 0);
assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
index 50fd188..522ab9f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -149,10 +149,9 @@
mService.onInitReady();
final Display display = mService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
- final DisplayWindowController dcw = new DisplayWindowController(display, mService);
// Display creation is driven by the ActivityManagerService via
// ActivityStackSupervisor. We emulate those steps here.
- mService.mRoot.createDisplayContent(display, dcw);
+ mService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
}
private void removeServices() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index aa0ecf8..65e1835 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -58,8 +58,8 @@
public static class TestDisplayContent extends DisplayContent {
private TestDisplayContent(Display display, WindowManagerService service,
- DisplayWindowController controller) {
- super(display, service, controller);
+ ActivityDisplay activityDisplay) {
+ super(display, service, activityDisplay);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 4394f9a..5c3368b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -360,21 +360,17 @@
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
synchronized (mWm.mGlobalLock) {
- return new DisplayContent(display, mWm, mock(DisplayWindowController.class));
+ return new DisplayContent(display, mWm, mock(ActivityDisplay.class));
}
}
/**
* Creates a {@link DisplayContent} with given display state and adds it to the system.
*
- * Unlike {@link #createNewDisplay()} that uses a mock {@link DisplayWindowController} to
- * initialize {@link DisplayContent}, this method used real controller object when the test
- * need to verify its related flows.
- *
* @param displayState For initializing the state of the display. See
* {@link Display#getState()}.
*/
- DisplayContent createNewDisplayWithController(int displayState) {
+ DisplayContent createNewDisplay(int displayState) {
// Leverage main display info & initialize it with display state for given displayId.
DisplayInfo displayInfo = new DisplayInfo();
displayInfo.copyFrom(mDisplayInfo);
@@ -382,11 +378,11 @@
final int displayId = sNextDisplayId++;
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
- final DisplayWindowController dcw = new DisplayWindowController(display, mWm);
synchronized (mWm.mGlobalLock) {
// Display creation is driven by DisplayWindowController via ActivityStackSupervisor.
// We skip those steps here.
- return mWm.mRoot.createDisplayContent(display, dcw);
+ final ActivityDisplay mockAd = mock(ActivityDisplay.class);
+ return mWm.mRoot.createDisplayContent(display, mockAd);
}
}