summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--api/system-current.txt1
-rw-r--r--api/test-current.txt1
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java2
-rw-r--r--core/java/android/animation/ValueAnimator.java17
-rw-r--r--core/java/android/app/AppOpsManager.java9
-rw-r--r--core/java/android/companion/BluetoothDeviceFilterUtils.java2
-rw-r--r--core/java/android/content/ContentProvider.java7
-rw-r--r--core/java/android/content/pm/PackageParser.java5
-rw-r--r--core/java/android/content/pm/PackageUserState.java6
-rw-r--r--core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java8
-rw-r--r--core/java/android/os/storage/IStorageManager.aidl4
-rw-r--r--core/java/android/os/storage/StorageManager.java89
-rw-r--r--core/java/android/view/SurfaceView.java6
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl2
-rw-r--r--core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java55
-rw-r--r--core/java/com/android/internal/util/CollectionUtils.java14
-rw-r--r--core/java/com/android/internal/view/TooltipPopup.java17
-rw-r--r--core/jni/android_util_Binder.cpp27
-rw-r--r--core/res/AndroidManifest.xml1
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java28
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java3
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/DozeServicePlugin.java21
-rw-r--r--packages/SystemUI/res/values-de/strings.xml4
-rw-r--r--packages/SystemUI/res/values-my/strings.xml2
-rw-r--r--packages/SystemUI/res/values/config.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeHost.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java130
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java61
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java76
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java10
-rw-r--r--services/core/java/com/android/server/AppOpsService.java22
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java64
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/am/UserController.java1
-rw-r--r--services/core/java/com/android/server/job/GrantedUriPermissions.java2
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerShellCommand.java2
-rw-r--r--services/core/java/com/android/server/job/JobServiceContext.java101
-rw-r--r--services/core/java/com/android/server/job/JobStore.java8
-rw-r--r--services/core/java/com/android/server/job/controllers/AppIdleController.java4
-rw-r--r--services/core/java/com/android/server/job/controllers/BatteryController.java4
-rw-r--r--services/core/java/com/android/server/job/controllers/ConnectivityController.java2
-rw-r--r--services/core/java/com/android/server/job/controllers/ContentObserverController.java2
-rw-r--r--services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java2
-rw-r--r--services/core/java/com/android/server/job/controllers/IdleController.java4
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java6
-rw-r--r--services/core/java/com/android/server/job/controllers/StorageController.java4
-rw-r--r--services/core/java/com/android/server/job/controllers/TimeController.java2
-rw-r--r--services/core/java/com/android/server/pm/InstantAppResolver.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java28
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java150
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java22
-rw-r--r--services/core/java/com/android/server/pm/Settings.java9
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java15
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java11
-rw-r--r--services/core/java/com/android/server/wm/BoundsAnimationController.java32
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java23
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java42
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java2
-rw-r--r--services/usage/java/com/android/server/usage/StorageStatsService.java2
-rw-r--r--telecomm/java/android/telecom/Log.java3
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java9
-rw-r--r--tests/JobSchedulerTestApp/res/layout/activity_main.xml8
-rw-r--r--tests/JobSchedulerTestApp/res/values/strings.xml2
-rw-r--r--tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java5
-rw-r--r--tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java3
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareSession.java1
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pManager.java2
97 files changed, 1151 insertions, 433 deletions
diff --git a/api/current.txt b/api/current.txt
index 05d9b9bf5a67..5dd3839b48a9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -69831,7 +69831,6 @@ package javax.net.ssl {
public abstract class SSLSocketFactory extends javax.net.SocketFactory {
ctor public SSLSocketFactory();
method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
- method public java.net.Socket createSocket(java.net.Socket, java.io.InputStream, boolean) throws java.io.IOException;
method public static synchronized javax.net.SocketFactory getDefault();
method public abstract java.lang.String[] getDefaultCipherSuites();
method public abstract java.lang.String[] getSupportedCipherSuites();
diff --git a/api/system-current.txt b/api/system-current.txt
index 6e27ffbf8967..dfad7a2d6883 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -73739,7 +73739,6 @@ package javax.net.ssl {
public abstract class SSLSocketFactory extends javax.net.SocketFactory {
ctor public SSLSocketFactory();
method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
- method public java.net.Socket createSocket(java.net.Socket, java.io.InputStream, boolean) throws java.io.IOException;
method public static synchronized javax.net.SocketFactory getDefault();
method public abstract java.lang.String[] getDefaultCipherSuites();
method public abstract java.lang.String[] getSupportedCipherSuites();
diff --git a/api/test-current.txt b/api/test-current.txt
index 5a265cc6bd84..9bafd5f74b14 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -70271,7 +70271,6 @@ package javax.net.ssl {
public abstract class SSLSocketFactory extends javax.net.SocketFactory {
ctor public SSLSocketFactory();
method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
- method public java.net.Socket createSocket(java.net.Socket, java.io.InputStream, boolean) throws java.io.IOException;
method public static synchronized javax.net.SocketFactory getDefault();
method public abstract java.lang.String[] getDefaultCipherSuites();
method public abstract java.lang.String[] getSupportedCipherSuites();
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index d71573f7ca50..c4193f647c32 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1473,7 +1473,7 @@ public final class Pm {
ClearDataObserver obs = new ClearDataObserver();
try {
mPm.freeStorageAndNotify(volumeUuid, sizeVal,
- StorageManager.FLAG_ALLOCATE_DEFY_RESERVED, obs);
+ StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED, obs);
synchronized (obs) {
while (!obs.finished) {
try {
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index e686a89accef..ee89ca8d55e2 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1469,24 +1469,21 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
if (!mSelfPulse) {
return;
}
- AnimationHandler handler = AnimationHandler.getInstance();
- handler.addOneShotCommitCallback(this);
+ getAnimationHandler().addOneShotCommitCallback(this);
}
private void removeAnimationCallback() {
if (!mSelfPulse) {
return;
}
- AnimationHandler handler = AnimationHandler.getInstance();
- handler.removeCallback(this);
+ getAnimationHandler().removeCallback(this);
}
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
- AnimationHandler handler = AnimationHandler.getInstance();
- handler.addAnimationFrameCallback(this, delay);
+ getAnimationHandler().addAnimationFrameCallback(this, delay);
}
/**
@@ -1643,4 +1640,12 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
public void setAllowRunningAsynchronously(boolean mayRunAsync) {
// It is up to subclasses to support this, if they can.
}
+
+ /**
+ * @return The {@link AnimationHandler} that will be used to schedule updates for this animator.
+ * @hide
+ */
+ public AnimationHandler getAnimationHandler() {
+ return AnimationHandler.getInstance();
+ }
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index e672ada3cbb4..b331d84010d0 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1947,4 +1947,13 @@ public class AppOpsManager {
public void finishOp(int op) {
finishOp(op, Process.myUid(), mContext.getOpPackageName());
}
+
+ /** @hide */
+ public boolean isOperationActive(int code, int uid, String packageName) {
+ try {
+ return mService.isOperationActive(code, uid, packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
index 3665d1b85bcb..4ee38fe4990e 100644
--- a/core/java/android/companion/BluetoothDeviceFilterUtils.java
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -58,7 +58,7 @@ public class BluetoothDeviceFilterUtils {
static boolean matchesAddress(String deviceAddress, BluetoothDevice device) {
final boolean result = deviceAddress == null
- || (device == null || !deviceAddress.equals(device.getAddress()));
+ || (device != null && deviceAddress.equals(device.getAddress()));
if (DEBUG) debugLogMatchResult(result, device, deviceAddress);
return result;
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 9d46da16965e..64e464c318d3 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -44,6 +44,7 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.MathUtils;
@@ -1376,6 +1377,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
* android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)},
* {@link ParcelFileDescriptor#createReliablePipe()}, or
* {@link ParcelFileDescriptor#createReliableSocketPair()}.
+ * <p>
+ * If you need to return a large file that isn't backed by a real file on
+ * disk, such as a file on a network share or cloud storage service,
+ * consider using
+ * {@link StorageManager#openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler)}
+ * which will let you to stream the content on-demand.
*
* <p class="note">For use in Intents, you will want to implement {@link #getType}
* to return the appropriate MIME type for the data returned here with
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9b0bab427478..fdb0f2bae64b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -6852,7 +6852,7 @@ public class PackageParser {
ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
}
ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
- ai.resourceDirs = state.resourceDirs;
+ ai.resourceDirs = state.overlayPaths;
}
public static ApplicationInfo generateApplicationInfo(Package p, int flags,
@@ -7000,6 +7000,7 @@ public class PackageParser {
return null;
}
if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
+ updateApplicationInfo(a.info.applicationInfo, flags, state);
return a.info;
}
// Make shallow copies so we can store the metadata safely
@@ -7088,6 +7089,7 @@ public class PackageParser {
return null;
}
if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
+ updateApplicationInfo(s.info.applicationInfo, flags, state);
return s.info;
}
// Make shallow copies so we can store the metadata safely
@@ -7183,6 +7185,7 @@ public class PackageParser {
if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
&& ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
|| p.info.uriPermissionPatterns == null)) {
+ updateApplicationInfo(p.info.applicationInfo, flags, state);
return p.info;
}
// Make shallow copies so we can store the metadata safely
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 4e53914a3c68..470336cc70c7 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -55,7 +55,7 @@ public class PackageUserState {
public ArraySet<String> disabledComponents;
public ArraySet<String> enabledComponents;
- public String[] resourceDirs;
+ public String[] overlayPaths;
public PackageUserState() {
installed = true;
@@ -83,8 +83,8 @@ public class PackageUserState {
installReason = o.installReason;
disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents);
enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents);
- resourceDirs =
- o.resourceDirs == null ? null : Arrays.copyOf(o.resourceDirs, o.resourceDirs.length);
+ overlayPaths =
+ o.overlayPaths == null ? null : Arrays.copyOf(o.overlayPaths, o.overlayPaths.length);
}
/**
diff --git a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
index c66a3a40718f..8296b7a915a4 100644
--- a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
+++ b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
@@ -15,13 +15,13 @@
*/
package android.hardware.camera2.dispatch;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.hardware.camera2.utils.UncheckedThrow;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
-import static com.android.internal.util.Preconditions.*;
-
/**
* Invoke a method on a dispatchable by its name (without knowing the {@code Method} ahead of time).
*
@@ -31,6 +31,7 @@ public class MethodNameInvoker<T> {
private final Dispatchable<T> mTarget;
private final Class<T> mTargetClass;
+ private final Method[] mTargetClassMethods;
private final ConcurrentHashMap<String, Method> mMethods =
new ConcurrentHashMap<>();
@@ -42,6 +43,7 @@ public class MethodNameInvoker<T> {
*/
public MethodNameInvoker(Dispatchable<T> target, Class<T> targetClass) {
mTargetClass = targetClass;
+ mTargetClassMethods = targetClass.getMethods();
mTarget = target;
}
@@ -68,7 +70,7 @@ public class MethodNameInvoker<T> {
Method targetMethod = mMethods.get(methodName);
if (targetMethod == null) {
- for (Method method : mTargetClass.getMethods()) {
+ for (Method method : mTargetClassMethods) {
// TODO future: match types of params if possible
if (method.getName().equals(methodName) &&
(params.length == method.getParameterTypes().length) ) {
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 92f7f319a14b..50855bb349d9 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -293,7 +293,7 @@ interface IStorageManager {
ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode) = 74;
long getCacheQuotaBytes(String volumeUuid, int uid) = 75;
long getCacheSizeBytes(String volumeUuid, int uid) = 76;
- long getAllocatableBytes(String volumeUuid, int flags) = 77;
- void allocateBytes(String volumeUuid, long bytes, int flags) = 78;
+ long getAllocatableBytes(String volumeUuid, int flags, String callingPackage) = 77;
+ void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) = 78;
void secdiscard(in String path) = 79;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 504673529238..f2aa113ea28e 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -29,6 +29,7 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.WorkerThread;
+import android.app.Activity;
import android.app.ActivityThread;
import android.content.ContentResolver;
import android.content.Context;
@@ -159,6 +160,12 @@ public class StorageManager {
* If the sending application has a specific storage device or allocation
* size in mind, they can optionally define {@link #EXTRA_UUID} or
* {@link #EXTRA_REQUESTED_BYTES}, respectively.
+ * <p>
+ * This intent should be launched using
+ * {@link Activity#startActivityForResult(Intent, int)} so that the user
+ * knows which app is requesting the storage space. The returned result will
+ * be {@link Activity#RESULT_OK} if the requested space was made available,
+ * or {@link Activity#RESULT_CANCELED} otherwise.
*/
@SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
@@ -1174,7 +1181,7 @@ public class StorageManager {
*
* @hide
*/
- public long getStorageCacheBytes(File path) {
+ public long getStorageCacheBytes(File path, @AllocateFlags int flags) {
final long cachePercent = Settings.Global.getInt(mResolver,
Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE, DEFAULT_CACHE_PERCENTAGE);
final long cacheBytes = (path.getTotalSpace() * cachePercent) / 100;
@@ -1182,7 +1189,16 @@ public class StorageManager {
final long maxCacheBytes = Settings.Global.getLong(mResolver,
Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES, DEFAULT_CACHE_MAX_BYTES);
- return Math.min(cacheBytes, maxCacheBytes);
+ final long result = Math.min(cacheBytes, maxCacheBytes);
+ if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
+ return 0;
+ } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED) != 0) {
+ return 0;
+ } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED) != 0) {
+ return result / 2;
+ } else {
+ return result;
+ }
}
/**
@@ -1467,15 +1483,26 @@ public class StorageManager {
}
/**
- * Opens seekable ParcelFileDescriptor that routes file operation requests to
- * ProxyFileDescriptorCallback.
+ * Opens a seekable {@link ParcelFileDescriptor} that proxies all low-level
+ * I/O requests back to the given {@link ProxyFileDescriptorCallback}.
+ * <p>
+ * This can be useful when you want to provide quick access to a large file
+ * that isn't backed by a real file on disk, such as a file on a network
+ * share, cloud storage service, etc. As an example, you could respond to a
+ * {@link ContentResolver#openFileDescriptor(android.net.Uri, String)}
+ * request by returning a {@link ParcelFileDescriptor} created with this
+ * method, and then stream the content on-demand as requested.
+ * <p>
+ * Another useful example might be where you have an encrypted file that
+ * you're willing to decrypt on-demand, but where you want to avoid
+ * persisting the cleartext version.
*
* @param mode The desired access mode, must be one of
- * {@link ParcelFileDescriptor#MODE_READ_ONLY},
- * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
- * {@link ParcelFileDescriptor#MODE_READ_WRITE}
- * @param callback Callback to process file operation requests issued on returned file
- * descriptor.
+ * {@link ParcelFileDescriptor#MODE_READ_ONLY},
+ * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
+ * {@link ParcelFileDescriptor#MODE_READ_WRITE}
+ * @param callback Callback to process file operation requests issued on
+ * returned file descriptor.
* @param handler Handler that invokes callback methods.
* @return Seekable ParcelFileDescriptor.
* @throws IOException
@@ -1487,7 +1514,6 @@ public class StorageManager {
return openProxyFileDescriptor(mode, callback, handler, null);
}
-
/** {@hide} */
@VisibleForTesting
public int getProxyFileDescriptorMountPointId() {
@@ -1628,17 +1654,26 @@ public class StorageManager {
public static final int FLAG_ALLOCATE_AGGRESSIVE = 1 << 0;
/**
- * Flag indicating that a disk space allocation request should defy any
- * reserved disk space.
+ * Flag indicating that a disk space allocation request should be allowed to
+ * clear up to all reserved disk space.
+ *
+ * @hide
+ */
+ public static final int FLAG_ALLOCATE_DEFY_ALL_RESERVED = 1 << 1;
+
+ /**
+ * Flag indicating that a disk space allocation request should be allowed to
+ * clear up to half of all reserved disk space.
*
* @hide
*/
- public static final int FLAG_ALLOCATE_DEFY_RESERVED = 1 << 1;
+ public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;
/** @hide */
@IntDef(flag = true, value = {
FLAG_ALLOCATE_AGGRESSIVE,
- FLAG_ALLOCATE_DEFY_RESERVED,
+ FLAG_ALLOCATE_DEFY_ALL_RESERVED,
+ FLAG_ALLOCATE_DEFY_HALF_RESERVED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AllocateFlags {}
@@ -1660,6 +1695,10 @@ public class StorageManager {
* persist, you can launch {@link #ACTION_MANAGE_STORAGE} with the
* {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help
* involve the user in freeing up disk space.
+ * <p>
+ * If you're progressively allocating an unbounded amount of storage space
+ * (such as when recording a video) you should avoid calling this method
+ * more than once every 30 seconds.
* <p class="note">
* Note: if your app uses the {@code android:sharedUserId} manifest feature,
* then allocatable space for all packages in your shared UID is tracked
@@ -1677,6 +1716,7 @@ public class StorageManager {
* @throws IOException when the storage device isn't present, or when it
* doesn't support allocating space.
*/
+ @WorkerThread
public @BytesLong long getAllocatableBytes(@NonNull UUID storageUuid)
throws IOException {
return getAllocatableBytes(storageUuid, 0);
@@ -1684,11 +1724,13 @@ public class StorageManager {
/** @hide */
@SystemApi
+ @WorkerThread
@SuppressLint("Doclava125")
public long getAllocatableBytes(@NonNull UUID storageUuid,
@RequiresPermission @AllocateFlags int flags) throws IOException {
try {
- return mStorageManager.getAllocatableBytes(convert(storageUuid), flags);
+ return mStorageManager.getAllocatableBytes(convert(storageUuid), flags,
+ mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
@@ -1699,6 +1741,7 @@ public class StorageManager {
/** @removed */
@Deprecated
+ @WorkerThread
@SuppressLint("Doclava125")
public long getAllocatableBytes(@NonNull File path,
@RequiresPermission @AllocateFlags int flags) throws IOException {
@@ -1717,6 +1760,10 @@ public class StorageManager {
* subject to race conditions. If possible, consider using
* {@link #allocateBytes(FileDescriptor, long, int)} which will guarantee
* that bytes are allocated to an opened file.
+ * <p>
+ * If you're progressively allocating an unbounded amount of storage space
+ * (such as when recording a video) you should avoid calling this method
+ * more than once every 60 seconds.
*
* @param storageUuid the UUID of the storage volume where you'd like to
* allocate disk space. The UUID for a specific path can be
@@ -1727,6 +1774,7 @@ public class StorageManager {
* trouble allocating the requested space.
* @see #getAllocatableBytes(UUID, int)
*/
+ @WorkerThread
public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes)
throws IOException {
allocateBytes(storageUuid, bytes, 0);
@@ -1734,11 +1782,13 @@ public class StorageManager {
/** @hide */
@SystemApi
+ @WorkerThread
@SuppressLint("Doclava125")
public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
@RequiresPermission @AllocateFlags int flags) throws IOException {
try {
- mStorageManager.allocateBytes(convert(storageUuid), bytes, flags);
+ mStorageManager.allocateBytes(convert(storageUuid), bytes, flags,
+ mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
} catch (RemoteException e) {
@@ -1748,6 +1798,7 @@ public class StorageManager {
/** @removed */
@Deprecated
+ @WorkerThread
@SuppressLint("Doclava125")
public void allocateBytes(@NonNull File path, @BytesLong long bytes,
@RequiresPermission @AllocateFlags int flags) throws IOException {
@@ -1766,6 +1817,10 @@ public class StorageManager {
* otherwise it will throw if fast allocation is not possible. Fast
* allocation is typically only supported in private app data directories,
* and on shared/external storage devices which are emulated.
+ * <p>
+ * If you're progressively allocating an unbounded amount of storage space
+ * (such as when recording a video) you should avoid calling this method
+ * more than once every 60 seconds.
*
* @param fd the open file that you'd like to allocate disk space for.
* @param bytes the number of bytes to allocate. This is the desired final
@@ -1779,12 +1834,14 @@ public class StorageManager {
* @see #getAllocatableBytes(UUID, int)
* @see Environment#isExternalStorageEmulated(File)
*/
+ @WorkerThread
public void allocateBytes(FileDescriptor fd, @BytesLong long bytes) throws IOException {
allocateBytes(fd, bytes, 0);
}
/** @hide */
@SystemApi
+ @WorkerThread
@SuppressLint("Doclava125")
public void allocateBytes(FileDescriptor fd, @BytesLong long bytes,
@RequiresPermission @AllocateFlags int flags) throws IOException {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ef78559e2b53..679a9cd92bc2 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1196,6 +1196,12 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
mBackgroundControl.deferTransactionUntil(handle, frame);
}
+ @Override
+ public void deferTransactionUntil(Surface barrier, long frame) {
+ super.deferTransactionUntil(barrier, frame);
+ mBackgroundControl.deferTransactionUntil(barrier, frame);
+ }
+
void updateBackgroundVisibility() {
if (mOpaque && mVisible) {
mBackgroundControl.show();
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 35d4ba81bd69..7a119b4351c0 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -48,4 +48,6 @@ interface IAppOpsService {
void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle);
void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in String[] exceptionPackages);
void removeUser(int userHandle);
+
+ boolean isOperationActive(int code, int uid, String packageName);
}
diff --git a/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
new file mode 100644
index 000000000000..931eb9901288
--- /dev/null
+++ b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 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.internal.graphics;
+
+import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
+import android.view.Choreographer;
+
+/**
+ * Provider of timing pulse that uses SurfaceFlinger Vsync Choreographer for frame callbacks.
+ *
+ * @hide
+ */
+public final class SfVsyncFrameCallbackProvider implements AnimationFrameCallbackProvider {
+
+ private final Choreographer mChoreographer = Choreographer.getSfInstance();
+
+ @Override
+ public void postFrameCallback(Choreographer.FrameCallback callback) {
+ mChoreographer.postFrameCallback(callback);
+ }
+
+ @Override
+ public void postCommitCallback(Runnable runnable) {
+ mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, runnable, null);
+ }
+
+ @Override
+ public long getFrameTime() {
+ return mChoreographer.getFrameTime();
+ }
+
+ @Override
+ public long getFrameDelay() {
+ return Choreographer.getFrameDelay();
+ }
+
+ @Override
+ public void setFrameDelay(long delay) {
+ Choreographer.setFrameDelay(delay);
+ }
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 96b443d28abc..1f84061a5978 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
@@ -101,7 +102,7 @@ public class CollectionUtils {
/**
* Returns the given list, or an immutable empty list if the provided list is null
*
- * This can be used to guaranty null-safety without paying the price of extra allocations
+ * This can be used to guarantee null-safety without paying the price of extra allocations
*
* @see Collections#emptyList
*/
@@ -110,6 +111,17 @@ public class CollectionUtils {
}
/**
+ * Returns the given set, or an immutable empty set if the provided set is null
+ *
+ * This can be used to guarantee null-safety without paying the price of extra allocations
+ *
+ * @see Collections#emptySet
+ */
+ public static @NonNull <T> Set<T> emptyIfNull(@Nullable Set<T> cur) {
+ return cur == null ? Collections.emptySet() : cur;
+ }
+
+ /**
* Returns the size of the given list, or 0 if the list is null
*/
public static int size(@Nullable Collection<?> cur) {
diff --git a/core/java/com/android/internal/view/TooltipPopup.java b/core/java/com/android/internal/view/TooltipPopup.java
index d834e6383acd..52357ac486c2 100644
--- a/core/java/com/android/internal/view/TooltipPopup.java
+++ b/core/java/com/android/internal/view/TooltipPopup.java
@@ -25,7 +25,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import android.widget.PopupWindow;
import android.widget.TextView;
public class TooltipPopup {
@@ -33,7 +32,6 @@ public class TooltipPopup {
private final Context mContext;
- private final PopupWindow mPopupWindow;
private final View mContentView;
private final TextView mMessageView;
@@ -45,8 +43,6 @@ public class TooltipPopup {
public TooltipPopup(Context context) {
mContext = context;
- mPopupWindow = new PopupWindow(context);
- mPopupWindow.setBackgroundDrawable(null);
mContentView = LayoutInflater.from(mContext).inflate(
com.android.internal.R.layout.tooltip, null);
mMessageView = (TextView) mContentView.findViewById(
@@ -74,16 +70,17 @@ public class TooltipPopup {
computePosition(anchorView, anchorX, anchorY, fromTouch, mLayoutParams);
- mPopupWindow.setContentView(mContentView);
- mPopupWindow.showAtLocation(
- anchorView, mLayoutParams.gravity, mLayoutParams.x, mLayoutParams.y);
+ WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+ wm.addView(mContentView, mLayoutParams);
}
public void hide() {
if (!isShowing()) {
return;
}
- mPopupWindow.dismiss();
+
+ WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+ wm.removeView(mContentView);
}
public View getContentView() {
@@ -91,7 +88,7 @@ public class TooltipPopup {
}
public boolean isShowing() {
- return mPopupWindow.isShowing();
+ return mContentView.getParent() != null;
}
public void updateContent(CharSequence tooltipText) {
@@ -100,6 +97,8 @@ public class TooltipPopup {
private void computePosition(View anchorView, int anchorX, int anchorY, boolean fromTouch,
WindowManager.LayoutParams outParams) {
+ outParams.token = anchorView.getWindowToken();
+
final int tooltipPreciseAnchorThreshold = mContext.getResources().getDimensionPixelOffset(
com.android.internal.R.dimen.tooltip_precise_anchor_threshold);
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index de67c50e7195..26b00344b789 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <android-base/stringprintf.h>
#include <binder/IInterface.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
@@ -194,10 +195,34 @@ static void report_exception(JNIEnv* env, jthrowable excep, const char* msg)
/*
* It's an Error: Reraise the exception and ask the runtime to abort.
*/
+
+ // Try to get the exception string. Sometimes logcat isn't available,
+ // so try to add it to the abort message.
+ std::string exc_msg = "(Unknown exception message)";
+ {
+ ScopedLocalRef<jclass> exc_class(env, env->GetObjectClass(excep));
+ jmethodID method_id = env->GetMethodID(exc_class.get(),
+ "toString",
+ "()Ljava/lang/String;");
+ ScopedLocalRef<jstring> jstr(
+ env,
+ reinterpret_cast<jstring>(
+ env->CallObjectMethod(excep, method_id)));
+ env->ExceptionClear(); // Just for good measure.
+ if (jstr.get() != nullptr) {
+ ScopedUtfChars jstr_utf(env, jstr.get());
+ exc_msg = jstr_utf.c_str();
+ }
+ }
+
env->Throw(excep);
ALOGE("java.lang.Error thrown during binder transaction (stack trace follows) : ");
env->ExceptionDescribe();
- env->FatalError("java.lang.Error thrown during binder transaction.");
+
+ std::string error_msg = base::StringPrintf(
+ "java.lang.Error thrown during binder transaction: %s",
+ exc_msg.c_str());
+ env->FatalError(error_msg.c_str());
}
bail:
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 004ecfcd12cf..b4c5025e2f64 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -454,6 +454,7 @@
<protected-broadcast android:name="com.android.server.NetworkTimeUpdateService.action.POLL" />
<protected-broadcast android:name="com.android.server.telecom.intent.action.CALLS_ADD_ENTRY" />
<protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" />
+ <protected-broadcast android:name="com.android.settings.bluetooth.ACTION_DISMISS_PAIRING" />
<protected-broadcast android:name="NotificationManagerService.TIMEOUT" />
<protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" />
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index 2a4ab0f550e5..3b29a6cd7b6c 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -20,6 +20,8 @@ import static android.companion.BluetoothDeviceFilterUtils.getDeviceDisplayNameI
import static android.companion.BluetoothDeviceFilterUtils.getDeviceMacAddress;
import static com.android.internal.util.ArrayUtils.isEmpty;
+import static com.android.internal.util.CollectionUtils.emptyIfNull;
+import static com.android.internal.util.CollectionUtils.size;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -154,6 +156,25 @@ public class DeviceDiscoveryService extends Service {
onReadyToShowUI();
}
+ // If filtering to get single device by mac address, also search in the set of already
+ // bonded devices to allow linking those directly
+ String singleMacAddressFilter = null;
+ if (mRequest.isSingleDevice()) {
+ int numFilters = size(mBluetoothFilters);
+ for (int i = 0; i < numFilters; i++) {
+ BluetoothDeviceFilter filter = mBluetoothFilters.get(i);
+ if (!TextUtils.isEmpty(filter.getAddress())) {
+ singleMacAddressFilter = filter.getAddress();
+ break;
+ }
+ }
+ }
+ if (singleMacAddressFilter != null) {
+ for (BluetoothDevice dev : emptyIfNull(mBluetoothAdapter.getBondedDevices())) {
+ onDeviceFound(DeviceFilterPair.findMatch(dev, mBluetoothFilters));
+ }
+ }
+
if (shouldScan(mBluetoothFilters)) {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
@@ -211,6 +232,8 @@ public class DeviceDiscoveryService extends Service {
}
private void onDeviceFound(@Nullable DeviceFilterPair device) {
+ if (device == null) return;
+
if (mDevicesFound.contains(device)) {
return;
}
@@ -444,12 +467,9 @@ public class DeviceDiscoveryService extends Service {
}
for (int i = 0; i < scanResults.size(); i++) {
- DeviceFilterPair<android.net.wifi.ScanResult> deviceFilterPair =
- DeviceFilterPair.findMatch(scanResults.get(i), mWifiFilters);
- if (deviceFilterPair != null) onDeviceFound(deviceFilterPair);
+ onDeviceFound(DeviceFilterPair.findMatch(scanResults.get(i), mWifiFilters));
}
}
-
}
}
}
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 06a65c4dbf21..c879100aef9c 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -341,7 +341,7 @@
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">^1</xliff:g> - <xliff:g id="TIME">^2</xliff:g> حتى يكتمل الشحن"</string>
<string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">^1</xliff:g> - <xliff:g id="TIME">^2</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"غير معروف"</string>
- <string name="battery_info_status_charging" msgid="1705179948350365604">"جاري الشحن"</string>
+ <string name="battery_info_status_charging" msgid="1705179948350365604">"جارٍ الشحن"</string>
<string name="battery_info_status_charging_lower" msgid="8689770213898117994">"جارٍ الشحن"</string>
<string name="battery_info_status_discharging" msgid="310932812698268588">"لا يتم الشحن"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"لا يتم الشحن"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 8b834eec5dde..fbdb394976dc 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -281,7 +281,7 @@
<string name="app_process_limit_title" msgid="4280600650253107163">"Límita processos en segon pla"</string>
<string name="show_all_anrs" msgid="28462979638729082">"Tots els errors sense resposta"</string>
<string name="show_all_anrs_summary" msgid="641908614413544127">"Informa que una aplicació en segon pla no respon"</string>
- <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Avisos del canal de notificacions"</string>
+ <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Mostra avisos del canal de notificacions"</string>
<string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Mostra un avís a la pantalla quan una app publica una notificació sense canal vàlid"</string>
<string name="force_allow_on_external" msgid="3215759785081916381">"Força permís d\'aplicacions a l\'emmagatzem. extern"</string>
<string name="force_allow_on_external_summary" msgid="3640752408258034689">"Permet que qualsevol aplicació es pugui escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index c73a44338ed0..36117ed3c706 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -28,12 +28,9 @@
<string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"אין חיבור לרשת, כי איכות הרשת נמוכה"</string>
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏כשל בחיבור Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"בעיית אימות"</string>
- <!-- no translation found for wifi_cant_connect (5410016875644565884) -->
- <skip />
- <!-- no translation found for wifi_cant_connect_to_ap (1222553274052685331) -->
- <skip />
- <!-- no translation found for wifi_check_password_try_again (516958988102584767) -->
- <skip />
+ <string name="wifi_cant_connect" msgid="5410016875644565884">"לא ניתן להתחבר"</string>
+ <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"לא ניתן להתחבר אל <xliff:g id="AP_NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_check_password_try_again" msgid="516958988102584767">"בדוק את הסיסמה ונסה שוב"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"מחוץ לטווח"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"לא יתבצע חיבור באופן אוטומטי"</string>
<string name="wifi_no_internet" msgid="3880396223819116454">"אין גישה לאינטרנט"</string>
@@ -45,8 +42,7 @@
<string name="wifi_connected_no_internet" msgid="3149853966840874992">"מחובר. אין אינטרנט"</string>
<string name="speed_label_very_slow" msgid="1867055264243608530">"איטית מאוד"</string>
<string name="speed_label_slow" msgid="813109590815810235">"איטית"</string>
- <!-- no translation found for speed_label_okay (2331665440671174858) -->
- <skip />
+ <string name="speed_label_okay" msgid="2331665440671174858">"אישור"</string>
<string name="speed_label_medium" msgid="3175763313268941953">"בינונית"</string>
<string name="speed_label_fast" msgid="7715732164050975057">"מהירה"</string>
<string name="speed_label_very_fast" msgid="2265363430784523409">"מהירה מאוד"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 5fc93d0ec17c..b2de42177ccc 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -28,12 +28,9 @@
<string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"Желі байланысының сапасы төмен болғандықтан қосылмады"</string>
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi байланысының қатесі"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Растау мәселесі"</string>
- <!-- no translation found for wifi_cant_connect (5410016875644565884) -->
- <skip />
- <!-- no translation found for wifi_cant_connect_to_ap (1222553274052685331) -->
- <skip />
- <!-- no translation found for wifi_check_password_try_again (516958988102584767) -->
- <skip />
+ <string name="wifi_cant_connect" msgid="5410016875644565884">"Қосылу мүмкін емес"</string>
+ <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"\"<xliff:g id="AP_NAME">%1$s</xliff:g>\" қолданбасына қосылу мүмкін емес"</string>
+ <string name="wifi_check_password_try_again" msgid="516958988102584767">"Құпия сөзді тексеріп, әрекетті қайталаңыз"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Аумақта жоқ"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Автоматты қосылмайды"</string>
<string name="wifi_no_internet" msgid="3880396223819116454">"Интернетпен байланыс жоқ"</string>
@@ -45,8 +42,7 @@
<string name="wifi_connected_no_internet" msgid="3149853966840874992">"Қосылған, интернет жоқ"</string>
<string name="speed_label_very_slow" msgid="1867055264243608530">"Өте баяу"</string>
<string name="speed_label_slow" msgid="813109590815810235">"Баяу"</string>
- <!-- no translation found for speed_label_okay (2331665440671174858) -->
- <skip />
+ <string name="speed_label_okay" msgid="2331665440671174858">"Жарайды"</string>
<string name="speed_label_medium" msgid="3175763313268941953">"Орташа"</string>
<string name="speed_label_fast" msgid="7715732164050975057">"Жылдам"</string>
<string name="speed_label_very_fast" msgid="2265363430784523409">"Өте жылдам"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 76541a195438..4e5873e21640 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -41,10 +41,10 @@
<string name="available_via_passpoint" msgid="1617440946846329613">"%1$s မှတစ်ဆင့်ရနိုင်သည်"</string>
<string name="wifi_connected_no_internet" msgid="3149853966840874992">"ချိတ်ဆက်ထားသည်၊ အင်တာနက်မရှိ"</string>
<string name="speed_label_very_slow" msgid="1867055264243608530">"အလွန်နှေး"</string>
- <string name="speed_label_slow" msgid="813109590815810235">"နှေးသည်"</string>
+ <string name="speed_label_slow" msgid="813109590815810235">"နှေး"</string>
<string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
<string name="speed_label_medium" msgid="3175763313268941953">"အတော်အသင့်"</string>
- <string name="speed_label_fast" msgid="7715732164050975057">"မြန်သည်"</string>
+ <string name="speed_label_fast" msgid="7715732164050975057">"မြန်"</string>
<string name="speed_label_very_fast" msgid="2265363430784523409">"အလွန်မြန်"</string>
<string name="bluetooth_disconnected" msgid="6557104142667339895">"ချိတ်ဆက်မှုပြတ်တောက်သည်"</string>
<string name="bluetooth_disconnecting" msgid="8913264760027764974">"အဆက်အသွယ်ဖြတ်တောက်သည်"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index bbd3569ed9cc..70cc95a2c2db 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -28,8 +28,8 @@
<string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"Sifatsiz tarmoq sababli ulanib bo‘lmadi"</string>
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi ulanishini o‘rnatib bo‘lmadi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Tasdiqdan o‘tishda muammo"</string>
- <string name="wifi_cant_connect" msgid="5410016875644565884">"Ulanib bo‘lmadi"</string>
- <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"“<xliff:g id="AP_NAME">%1$s</xliff:g>” tarmog‘iga ulanib bo‘lmadi"</string>
+ <string name="wifi_cant_connect" msgid="5410016875644565884">"Tarmoqqa ulanilmadi"</string>
+ <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"“<xliff:g id="AP_NAME">%1$s</xliff:g>” nomli tarmoqqa ulanilmadi"</string>
<string name="wifi_check_password_try_again" msgid="516958988102584767">"Parolni tekshirib, qaytadan urining"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Xizmat doirasidan tashqarida"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Avtomatik ravishda ulanilmaydi"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index 9d09737a14dc..e067de1a5e7a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -34,6 +34,8 @@ public final class CategoryKey {
public static final String CATEGORY_SOUND = "com.android.settings.category.ia.sound";
public static final String CATEGORY_STORAGE = "com.android.settings.category.ia.storage";
public static final String CATEGORY_SECURITY = "com.android.settings.category.ia.security";
+ public static final String CATEGORY_SECURITY_LOCKSCREEN =
+ "com.android.settings.category.ia.lockscreen";
public static final String CATEGORY_ACCOUNT = "com.android.settings.category.ia.accounts";
public static final String CATEGORY_SYSTEM = "com.android.settings.category.ia.system";
public static final String CATEGORY_SYSTEM_LANGUAGE =
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
index 40353e7489b4..9fc8a9607cba 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
@@ -54,13 +54,14 @@ public class CategoryKeyTest {
allKeys.add(CategoryKey.CATEGORY_SOUND);
allKeys.add(CategoryKey.CATEGORY_STORAGE);
allKeys.add(CategoryKey.CATEGORY_SECURITY);
+ allKeys.add(CategoryKey.CATEGORY_SECURITY_LOCKSCREEN);
allKeys.add(CategoryKey.CATEGORY_ACCOUNT);
allKeys.add(CategoryKey.CATEGORY_SYSTEM);
allKeys.add(CategoryKey.CATEGORY_SYSTEM_LANGUAGE);
allKeys.add(CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT);
// DO NOT REMOVE ANYTHING ABOVE
- assertThat(allKeys.size()).isEqualTo(13);
+ assertThat(allKeys.size()).isEqualTo(14);
}
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DozeServicePlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DozeServicePlugin.java
new file mode 100644
index 000000000000..3ca5690af474
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DozeServicePlugin.java
@@ -0,0 +1,21 @@
+package com.android.systemui.plugins;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+@ProvidesInterface(action = DozeServicePlugin.ACTION, version = DozeServicePlugin.VERSION)
+public interface DozeServicePlugin extends Plugin {
+ String ACTION = "com.android.systemui.action.PLUGIN_DOZE";
+ int VERSION = 1;
+
+ public interface RequestDoze {
+ void onRequestShowDoze();
+
+ void onRequestHideDoze();
+ }
+
+ void onDreamingStarted();
+
+ void onDreamingStopped();
+
+ void setDozeRequester(RequestDoze requester);
+}
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 96849d3b66c0..9b28bdaa0e03 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -161,7 +161,9 @@
<string name="accessibility_no_sims" msgid="3957997018324995781">"Keine SIM-Karte"</string>
<string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Netzwerk des Mobilfunkanbieters wird gewechselt"</string>
<string name="accessibility_battery_details" msgid="7645516654955025422">"Akkudetails öffnen"</string>
- <string name="accessibility_battery_level" msgid="7451474187113371965">"Akku bei <xliff:g id="NUMBER">%d</xliff:g> Prozent."</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for accessibility_battery_level (7451474187113371965) -->
+ <skip />
<!-- String.format failed for translation -->
<!-- no translation found for accessibility_battery_level_charging (1147587904439319646) -->
<skip />
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 11f82648c732..459b61caa31a 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -553,7 +553,7 @@
<string name="notification_channel_disabled" msgid="2139193533791840539">"သင်သည် ဤအကြောင်းကြားချက်များကို နောက်ထပ် လက်ခံရရှိတော့မည် မဟုတ်ပါ"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"အကြောင်းကြားချက် အမျိုးအစား <xliff:g id="NUMBER">%d</xliff:g> ခု"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"ဤအက်ပ်တွင် အကြောင်းကြားချက် အမျိုးအစားများ မရှိပါ"</string>
- <string name="notification_unblockable_desc" msgid="3561016061737896906">"ဤအက်ပ်မှပို့သော အကြောင်းအကြားချက်များကို ပိတ်ထား၍မရပါ"</string>
+ <string name="notification_unblockable_desc" msgid="3561016061737896906">"ဤအက်ပ်မှပို့သော အကြောင်းကြားချက်များကို ပိတ်ထား၍မရပါ"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
<item quantity="other">ဤအက်ပ်ရှိ အကြောင်းကြားချက်အမျိုးအစား <xliff:g id="NUMBER_1">%d</xliff:g> ခု အနက်မှ ၁ ခု</item>
<item quantity="one">ဤအက်ပ်ရှိ အကြောင်းကြားချက်အမျိုးအစား <xliff:g id="NUMBER_0">%d</xliff:g> ခု အနက်မှ ၁ ခု</item>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d3cbe4aa578f..81ca23082367 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -262,6 +262,9 @@
<!-- Doze: alpha to apply to small icons when dozing -->
<integer name="doze_small_icon_alpha">222</integer><!-- 87% of 0xff -->
+ <!-- Doze: whether the double tap sensor reports 2D touch coordinates -->
+ <bool name="doze_double_tap_reports_touch_coordinates">false</bool>
+
<!-- Hotspot tile: number of days to show after feature is used. -->
<integer name="days_to_show_hotspot_tile">30</integer>
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 3e424d05373a..5aaa6c78f5fd 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -38,6 +38,8 @@ public interface DozeHost {
void setAnimateWakeup(boolean animateWakeup);
+ void onDoubleTap(float x, float y);
+
interface Callback {
default void onNotificationHeadsUp() {}
default void onPowerSaveChanged(boolean active) {}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 73f522244a60..23da716706d3 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -81,17 +81,18 @@ public class DozeSensors {
mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
null /* setting */,
dozeParameters.getPulseOnSigMotion(),
- DozeLog.PULSE_REASON_SENSOR_SIGMOTION),
+ DozeLog.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */),
mPickupSensor = new TriggerSensor(
mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
Settings.Secure.DOZE_PULSE_ON_PICK_UP,
config.pulseOnPickupAvailable(),
- DozeLog.PULSE_REASON_SENSOR_PICKUP),
+ DozeLog.PULSE_REASON_SENSOR_PICKUP, false /* touchCoords */),
new TriggerSensor(
findSensorWithType(config.doubleTapSensorType()),
Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP,
true /* configured */,
- DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP)
+ DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP,
+ dozeParameters.doubleTapReportsTouchCoordinates())
};
mProxSensor = new ProxSensor();
@@ -207,16 +208,19 @@ public class DozeSensors {
final boolean mConfigured;
final int mPulseReason;
final String mSetting;
+ final boolean mReportsTouchCoordinates;
private boolean mRequested;
private boolean mRegistered;
private boolean mDisabled;
- public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason) {
+ public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason,
+ boolean reportsTouchCoordinates) {
mSensor = sensor;
mSetting = setting;
mConfigured = configured;
mPulseReason = pulseReason;
+ mReportsTouchCoordinates = reportsTouchCoordinates;
}
public void setListening(boolean listen) {
@@ -276,7 +280,13 @@ public class DozeSensors {
}
mRegistered = false;
- mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck);
+ float screenX = -1;
+ float screenY = -1;
+ if (mReportsTouchCoordinates && event.values.length >= 2) {
+ screenX = event.values[0];
+ screenY = event.values[1];
+ }
+ mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck, screenX, screenY);
updateListener(); // reregister, this sensor only fires once
}));
}
@@ -309,7 +319,12 @@ public class DozeSensors {
* Called when a sensor requests a pulse
* @param pulseReason Requesting sensor, e.g. {@link DozeLog#PULSE_REASON_SENSOR_PICKUP}
* @param sensorPerformedProxCheck true if the sensor already checked for FAR proximity.
+ * @param screenX the location on the screen where the sensor fired or -1
+ * if the sensor doesn't support reporting screen locations.
+ * @param screenY the location on the screen where the sensor fired or -1
+ * if the sensor doesn't support reporting screen locations.
*/
- void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck);
+ void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck,
+ float screenX, float screenY);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 3271caf598cf..d9fb087a6041 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -16,23 +16,27 @@
package com.android.systemui.doze;
+import android.content.Context;
import android.os.PowerManager;
import android.os.SystemClock;
import android.service.dreams.DreamService;
import android.util.Log;
import com.android.systemui.Dependency;
-import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.DozeServicePlugin;
import com.android.systemui.plugins.PluginManager;
-
+import com.android.systemui.plugins.DozeServicePlugin.RequestDoze;
+import com.android.systemui.plugins.PluginListener;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-public class DozeService extends DreamService implements DozeMachine.Service {
+public class DozeService extends DreamService
+ implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> {
private static final String TAG = "DozeService";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private DozeMachine mDozeMachine;
+ private DozeServicePlugin mDozePlugin;
public DozeService() {
setDebug(DEBUG);
@@ -48,23 +52,44 @@ public class DozeService extends DreamService implements DozeMachine.Service {
finish();
return;
}
-
+ Dependency.get(PluginManager.class).addPluginListener(this,
+ DozeServicePlugin.class, false /* Allow multiple */);
mDozeMachine = new DozeFactory().assembleMachine(this);
}
@Override
+ public void onPluginConnected(DozeServicePlugin plugin, Context pluginContext) {
+ mDozePlugin = plugin;
+ mDozePlugin.setDozeRequester(this);
+ }
+
+ @Override
+ public void onPluginDisconnected(DozeServicePlugin plugin) {
+ if (mDozePlugin != null) {
+ mDozePlugin.onDreamingStopped();
+ mDozePlugin = null;
+ }
+ }
+
+ @Override
public void onDreamingStarted() {
super.onDreamingStarted();
mDozeMachine.requestState(DozeMachine.State.INITIALIZED);
startDozing();
setDozeScreenBrightness(getResources().getInteger(
com.android.internal.R.integer.config_screenBrightnessDoze));
+ if (mDozePlugin != null) {
+ mDozePlugin.onDreamingStarted();
+ }
}
@Override
public void onDreamingStopped() {
super.onDreamingStopped();
mDozeMachine.requestState(DozeMachine.State.FINISH);
+ if (mDozePlugin != null) {
+ mDozePlugin.onDreamingStopped();
+ }
}
@Override
@@ -79,4 +104,18 @@ public class DozeService extends DreamService implements DozeMachine.Service {
PowerManager pm = getSystemService(PowerManager.class);
pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
}
+
+ @Override
+ public void onRequestShowDoze() {
+ if (mDozeMachine != null) {
+ mDozeMachine.requestState(DozeMachine.State.DOZE_AOD);
+ }
+ }
+
+ @Override
+ public void onRequestHideDoze() {
+ if (mDozeMachine != null) {
+ mDozeMachine.requestState(DozeMachine.State.DOZE);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 693a690d7f59..ae936db7b0e2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -98,12 +98,14 @@ public class DozeTriggers implements DozeMachine.Part {
requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */);
}
- private void onSensor(int pulseReason, boolean sensorPerformedProxCheck) {
+ private void onSensor(int pulseReason, boolean sensorPerformedProxCheck,
+ float screenX, float screenY) {
boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
if (isDoubleTap) {
+ mDozeHost.onDoubleTap(screenX, screenY);
mMachine.wakeUp();
} else {
mDozeHost.extendPulse();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b8de9f33f900..6d10d9413e66 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1868,12 +1868,7 @@ public class KeyguardViewMediator extends SystemUI {
+ " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags));
}
- if (!(mContext instanceof Activity)) {
- final int finalFlags = flags;
- mUiOffloadThread.submit(() -> {
- mStatusBarManager.disable(finalFlags);
- });
- }
+ mStatusBarManager.disable(flags);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
index 867c15c4736f..6733421a8d0e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
@@ -21,12 +21,15 @@ import static android.view.WindowManager.INPUT_CONSUMER_PIP;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
+import android.view.BatchedInputEventReceiver;
+import android.view.Choreographer;
import android.view.InputChannel;
import android.view.InputEvent;
-import android.view.InputEventReceiver;
import android.view.IWindowManager;
import android.view.MotionEvent;
+import com.android.systemui.recents.misc.Utilities;
+
import java.io.PrintWriter;
/**
@@ -52,12 +55,13 @@ public class InputConsumerController {
}
/**
- * Input handler used for the PiP input consumer.
+ * Input handler used for the PiP input consumer. Input events are batched and consumed with the
+ * SurfaceFlinger vsync.
*/
- private final class PipInputEventReceiver extends InputEventReceiver {
+ private final class PipInputEventReceiver extends BatchedInputEventReceiver {
public PipInputEventReceiver(InputChannel inputChannel, Looper looper) {
- super(inputChannel, looper);
+ super(inputChannel, looper, Choreographer.getSfInstance());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 013b9ac70118..0f69f471bc24 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -573,13 +573,11 @@ public class PipMenuActivity extends Activity {
}
private void cancelDelayedFinish() {
- View v = getWindow().getDecorView();
- v.removeCallbacks(mFinishRunnable);
+ mHandler.removeCallbacks(mFinishRunnable);
}
private void repostDelayedFinish(long delay) {
- View v = getWindow().getDecorView();
- v.removeCallbacks(mFinishRunnable);
- v.postDelayed(mFinishRunnable, delay);
+ mHandler.removeCallbacks(mFinishRunnable);
+ mHandler.postDelayed(mFinishRunnable, delay);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 9fa7ff61a13d..b8771d7e0fb6 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -22,6 +22,7 @@ import static com.android.systemui.Interpolators.FAST_OUT_LINEAR_IN;
import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;
+import android.animation.AnimationHandler;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
@@ -36,14 +37,15 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Debug;
import android.os.Handler;
+import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
-import android.view.Choreographer;
import android.view.animation.Interpolator;
-import com.android.internal.os.BackgroundThread;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.internal.os.SomeArgs;
import com.android.internal.policy.PipSnapAlgorithm;
-import com.android.internal.view.SurfaceFlingerVsyncChoreographer;
+import com.android.systemui.recents.misc.ForegroundThread;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -52,7 +54,7 @@ import java.io.PrintWriter;
/**
* A helper to animate and manipulate the PiP.
*/
-public class PipMotionHelper {
+public class PipMotionHelper implements Handler.Callback {
private static final String TAG = "PipMotionHelper";
private static final boolean DEBUG = false;
@@ -74,38 +76,34 @@ public class PipMotionHelper {
// The fraction of the stack height that the user has to drag offscreen to dismiss the PiP
private static final float DISMISS_OFFSCREEN_FRACTION = 0.3f;
+ private static final int MSG_RESIZE_IMMEDIATE = 1;
+ private static final int MSG_RESIZE_ANIMATE = 2;
+
private Context mContext;
private IActivityManager mActivityManager;
- private SurfaceFlingerVsyncChoreographer mVsyncChoreographer;
private Handler mHandler;
private PipMenuActivityController mMenuController;
private PipSnapAlgorithm mSnapAlgorithm;
private FlingAnimationUtils mFlingAnimationUtils;
+ private AnimationHandler mAnimationHandler;
private final Rect mBounds = new Rect();
private final Rect mStableInsets = new Rect();
private ValueAnimator mBoundsAnimator = null;
- private ValueAnimator.AnimatorUpdateListener mUpdateBoundsListener =
- new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mBounds.set((Rect) animation.getAnimatedValue());
- }
- };
public PipMotionHelper(Context context, IActivityManager activityManager,
PipMenuActivityController menuController, PipSnapAlgorithm snapAlgorithm,
FlingAnimationUtils flingAnimationUtils) {
mContext = context;
- mHandler = BackgroundThread.getHandler();
+ mHandler = new Handler(ForegroundThread.get().getLooper(), this);
mActivityManager = activityManager;
mMenuController = menuController;
mSnapAlgorithm = snapAlgorithm;
mFlingAnimationUtils = flingAnimationUtils;
- mVsyncChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, mContext.getDisplay(),
- Choreographer.getInstance());
+ mAnimationHandler = new AnimationHandler();
+ mAnimationHandler.setProvider(new SfVsyncFrameCallbackProvider());
onConfigurationChanged();
}
@@ -252,8 +250,7 @@ public class PipMotionHelper {
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
0 /* velocityX */, velocityY);
if (!mBounds.equals(toBounds)) {
- mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN,
- mUpdateBoundsListener);
+ mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN);
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
distanceBetweenRectOffsets(mBounds, toBounds),
velocityY);
@@ -271,7 +268,7 @@ public class PipMotionHelper {
Rect toBounds = getClosestMinimizedBounds(mBounds, movementBounds);
if (!mBounds.equals(toBounds)) {
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds,
- MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN, mUpdateBoundsListener);
+ MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN);
if (updateListener != null) {
mBoundsAnimator.addUpdateListener(updateListener);
}
@@ -289,8 +286,7 @@ public class PipMotionHelper {
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
velocityX, velocityY);
if (!mBounds.equals(toBounds)) {
- mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN,
- mUpdateBoundsListener);
+ mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN);
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
distanceBetweenRectOffsets(mBounds, toBounds),
velocity);
@@ -314,7 +310,7 @@ public class PipMotionHelper {
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds);
if (!mBounds.equals(toBounds)) {
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, SNAP_STACK_DURATION,
- FAST_OUT_SLOW_IN, mUpdateBoundsListener);
+ FAST_OUT_SLOW_IN);
if (updateListener != null) {
mBoundsAnimator.addUpdateListener(updateListener);
}
@@ -379,7 +375,7 @@ public class PipMotionHelper {
Rect toBounds = new Rect(pipBounds);
toBounds.offsetTo(p.x, p.y);
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, DRAG_TO_DISMISS_STACK_DURATION,
- FAST_OUT_LINEAR_IN, mUpdateBoundsListener);
+ FAST_OUT_LINEAR_IN);
mBoundsAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -411,16 +407,20 @@ public class PipMotionHelper {
* Creates an animation to move the PiP to give given {@param toBounds}.
*/
private ValueAnimator createAnimationToBounds(Rect fromBounds, Rect toBounds, int duration,
- Interpolator interpolator, ValueAnimator.AnimatorUpdateListener updateListener) {
- ValueAnimator anim = ValueAnimator.ofObject(RECT_EVALUATOR, fromBounds, toBounds);
+ Interpolator interpolator) {
+ ValueAnimator anim = new ValueAnimator() {
+ @Override
+ public AnimationHandler getAnimationHandler() {
+ return mAnimationHandler;
+ }
+ };
+ anim.setObjectValues(fromBounds, toBounds);
+ anim.setEvaluator(RECT_EVALUATOR);
anim.setDuration(duration);
anim.setInterpolator(interpolator);
anim.addUpdateListener((ValueAnimator animation) -> {
resizePipUnchecked((Rect) animation.getAnimatedValue());
});
- if (updateListener != null) {
- anim.addUpdateListener(updateListener);
- }
return anim;
}
@@ -433,14 +433,9 @@ public class PipMotionHelper {
+ " callers=\n" + Debug.getCallers(5, " "));
}
if (!toBounds.equals(mBounds)) {
- mVsyncChoreographer.scheduleAtSfVsync(() -> {
- try {
- mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */);
- mBounds.set(toBounds);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not resize pinned stack to bounds: " + toBounds, e);
- }
- });
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = toBounds;
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_IMMEDIATE, args));
}
}
@@ -453,23 +448,10 @@ public class PipMotionHelper {
+ " duration=" + duration + " callers=\n" + Debug.getCallers(5, " "));
}
if (!toBounds.equals(mBounds)) {
- mHandler.post(() -> {
- try {
- StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
- if (stackInfo == null) {
- // In the case where we've already re-expanded or dismissed the PiP, then
- // just skip the resize
- return;
- }
-
- mActivityManager.resizeStack(PINNED_STACK_ID, toBounds,
- false /* allowResizeInDockedMode */, true /* preserveWindows */,
- true /* animate */, duration);
- mBounds.set(toBounds);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e);
- }
- });
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = toBounds;
+ args.argi1 = duration;
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
}
}
@@ -524,6 +506,50 @@ public class PipMotionHelper {
return PointF.length(r1.left - r2.left, r1.top - r2.top);
}
+ /**
+ * Handles messages to be processed on the background thread.
+ */
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_RESIZE_IMMEDIATE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Rect toBounds = (Rect) args.arg1;
+ try {
+ mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */);
+ mBounds.set(toBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not resize pinned stack to bounds: " + toBounds, e);
+ }
+ return true;
+ }
+
+ case MSG_RESIZE_ANIMATE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Rect toBounds = (Rect) args.arg1;
+ int duration = args.argi1;
+ try {
+ StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ if (stackInfo == null) {
+ // In the case where we've already re-expanded or dismissed the PiP, then
+ // just skip the resize
+ return true;
+ }
+
+ mActivityManager.resizeStack(PINNED_STACK_ID, toBounds,
+ false /* allowResizeInDockedMode */, true /* preserveWindows */,
+ true /* animate */, duration);
+ mBounds.set(toBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e);
+ }
+ return true;
+ }
+
+ default:
+ return false;
+ }
+ }
+
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
index 603f66beca63..315a815af100 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
@@ -18,12 +18,14 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.plugins.qs.QSTile.SlashState;
import com.android.systemui.qs.SlashDrawable;
public class SlashImageView extends ImageView {
- private SlashDrawable mSlash;
+ @VisibleForTesting
+ protected SlashDrawable mSlash;
public SlashImageView(Context context) {
super(context);
@@ -38,10 +40,13 @@ public class SlashImageView extends ImageView {
@Override
public void setImageDrawable(Drawable drawable) {
- if (mSlash != null) {
- mSlash.setDrawable(drawable);
- } else {
+ if (drawable == null) {
+ mSlash = null;
+ super.setImageDrawable(null);
+ } else if (mSlash == null) {
super.setImageDrawable(drawable);
+ } else {
+ mSlash.setDrawable(drawable);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 703be27ad173..36677a46ed9f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -183,12 +183,6 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
@Override
public void onBluetoothDevicesChanged() {
- mUiHandler.post(new Runnable() {
- @Override
- public void run() {
- mDetailAdapter.updateItems();
- }
- });
refreshState();
if (isShowingDetail()) {
mDetailAdapter.updateItems();
@@ -202,6 +196,9 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
}
protected class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
+ // We probably won't ever have space in the UI for more than 20 devices, so don't
+ // get info for them.
+ private static final int MAX_DEVICES = 20;
private QSDetailItems mItems;
@Override
@@ -264,13 +261,14 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
final Collection<CachedBluetoothDevice> devices = mController.getDevices();
if (devices != null) {
int connectedDevices = 0;
+ int count = 0;
for (CachedBluetoothDevice device : devices) {
- if (device.getBondState() == BluetoothDevice.BOND_NONE) continue;
+ if (mController.getBondState(device) == BluetoothDevice.BOND_NONE) continue;
final Item item = new Item();
item.icon = R.drawable.ic_qs_bluetooth_on;
item.line1 = device.getName();
item.tag = device;
- int state = device.getMaxConnectionState();
+ int state = mController.getMaxConnectionState(device);
if (state == BluetoothProfile.STATE_CONNECTED) {
item.icon = R.drawable.ic_qs_bluetooth_connected;
item.line2 = mContext.getString(R.string.quick_settings_connected);
@@ -284,6 +282,9 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
} else {
items.add(item);
}
+ if (++count == MAX_DEVICES) {
+ break;
+ }
}
}
mItems.setItems(items.toArray(new Item[items.size()]));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 1f13830ec1cc..c66b2dd8eec5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -154,6 +154,13 @@ public class SystemServicesProxy {
Canvas mBgProtectionCanvas;
private final Handler mHandler = new H();
+ private final Runnable mGcRunnable = new Runnable() {
+ @Override
+ public void run() {
+ System.gc();
+ System.runFinalization();
+ }
+ };
private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
@@ -365,13 +372,7 @@ public class SystemServicesProxy {
* Requests a gc() from the background thread.
*/
public void gc() {
- BackgroundThread.getHandler().post(new Runnable() {
- @Override
- public void run() {
- System.gc();
- System.runFinalization();
- }
- });
+ BackgroundThread.getHandler().post(mGcRunnable);
}
/**
@@ -799,11 +800,8 @@ public class SystemServicesProxy {
if (RecentsDebugFlags.Static.EnableMockTasks) return;
// Remove the task.
- BackgroundThread.getHandler().post(new Runnable() {
- @Override
- public void run() {
- mAm.removeTask(taskId);
- }
+ mUiOffloadThread.submit(() -> {
+ mAm.removeTask(taskId);
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
index 1f82c1677029..308cece1dfdd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
@@ -20,9 +20,9 @@ import android.content.Context;
import android.os.UserHandle;
import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.BackgroundThread;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.PackagesChangedEvent;
+import com.android.systemui.recents.misc.ForegroundThread;
/**
* The package monitor listens for changes from PackageManager to update the contents of the
@@ -36,7 +36,7 @@ public class RecentsPackageMonitor extends PackageMonitor {
// We register for events from all users, but will cross-reference them with
// packages for the current user and any profiles they have. Ensure that events are
// handled in a background thread.
- register(context, BackgroundThread.get().getLooper(), UserHandle.ALL, true);
+ register(context, ForegroundThread.get().getLooper(), UserHandle.ALL, true);
} catch (IllegalStateException e) {
e.printStackTrace();
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 4022718865e0..da0a43551f1f 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -25,6 +25,8 @@ import android.view.View;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -56,6 +58,7 @@ public class Divider extends SystemUI {
SystemServicesProxy ssp = Recents.getSystemServices();
ssp.registerDockedStackListener(mDockDividerVisibilityListener);
mForcedResizableController = new ForcedResizableInfoActivityController(mContext);
+ EventBus.getDefault().register(this);
}
@Override
@@ -153,6 +156,18 @@ public class Divider extends SystemUI {
mWindowManager.setTouchable((mHomeStackResizable || !mMinimized) && !mAdjustedForIme);
}
+ /**
+ * Workaround for b/62528361, at the time RecentsDrawnEvent is sent, it may happen before a
+ * configuration change to the Divider, and internally, the event will be posted to the
+ * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
+ * register the event handler here and proxy the event to the current DividerView.
+ */
+ public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
+ if (mView != null) {
+ mView.onRecentsDrawn();
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.print(" mVisible="); pw.println(mVisible);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 09f459b0b07b..45835d51ff90 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -1224,7 +1224,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mSnapAlgorithm.getMiddleTarget());
}
- public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
+ public void onRecentsDrawn() {
if (mState.animateAfterRecentsDrawn) {
mState.animateAfterRecentsDrawn = false;
updateDockSide();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index d7e7abe4fd9c..6b7397b3f8ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -157,6 +157,10 @@ public class DozeParameters {
return 2 * getPulseVisibleDuration();
}
+ public boolean doubleTapReportsTouchCoordinates() {
+ return mContext.getResources().getBoolean(R.bool.doze_double_tap_reports_touch_coordinates);
+ }
+
/**
* Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index e8b6e079e261..f6032d3c9bc7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -32,7 +32,6 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCE
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
-import android.R.style;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.NonNull;
@@ -5325,6 +5324,37 @@ public class StatusBar extends SystemUI implements DemoMode,
mAnimateWakeup = animateWakeup;
}
+ @Override
+ public void onDoubleTap(float screenX, float screenY) {
+ if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
+ && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
+ mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2);
+ float viewX = screenX - mTmpInt2[0];
+ float viewY = screenY - mTmpInt2[1];
+ if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth()
+ && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) {
+ dispatchDoubleTap(viewX, viewY);
+ }
+ }
+ }
+
+ public void dispatchDoubleTap(float viewX, float viewY) {
+ dispatchTap(mAmbientIndicationContainer, viewX, viewY);
+ dispatchTap(mAmbientIndicationContainer, viewX, viewY);
+ }
+
+ private void dispatchTap(View view, float x, float y) {
+ long now = SystemClock.elapsedRealtime();
+ dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN);
+ dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_UP);
+ }
+
+ private void dispatchTouchEvent(View view, float x, float y, long now, int action) {
+ MotionEvent ev = MotionEvent.obtain(now, now, action, x, y, 0 /* meta */);
+ view.dispatchTouchEvent(ev);
+ ev.recycle();
+ }
+
private boolean shouldAnimateWakeup() {
return mAnimateWakeup;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 7d69a349f01d..9b0307d6522e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -94,6 +94,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private boolean mLastBouncerDismissible;
protected boolean mLastRemoteInputActive;
private boolean mLastDozing;
+ private boolean mLastDeferScrimFadeOut;
private OnDismissAction mAfterKeyguardGoneAction;
private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>();
@@ -371,7 +372,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
mFingerprintUnlockController.startKeyguardFadingAway();
mBouncer.hide(true /* destroyView */);
- updateStates();
if (wakeUnlockPulsing) {
mStatusBarWindowManager.setKeyguardFadingAway(true);
mStatusBar.fadeKeyguardWhilePulsing();
@@ -403,6 +403,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mFingerprintUnlockController.finishKeyguardFadingAway();
}
}
+ updateStates();
mStatusBarWindowManager.setKeyguardShowing(false);
mViewMediatorCallback.keyguardGone();
}
@@ -574,7 +575,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mLastBouncerDismissible = bouncerDismissible;
mLastRemoteInputActive = remoteInputActive;
mLastDozing = mDozing;
-
+ mLastDeferScrimFadeOut = mDeferScrimFadeOut;
mStatusBar.onKeyguardViewManagerStatesUpdated();
}
@@ -582,15 +583,16 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
* @return Whether the navigation bar should be made visible based on the current state.
*/
protected boolean isNavBarVisible() {
- return !(mShowing && !mOccluded) && !mDozing || mBouncer.isShowing() || mRemoteInputActive;
+ return (!(mShowing && !mOccluded) && !mDozing || mBouncer.isShowing() || mRemoteInputActive)
+ && !mDeferScrimFadeOut;
}
/**
* @return Whether the navigation bar was made visible based on the last known state.
*/
protected boolean getLastNavBarVisible() {
- return !(mLastShowing && !mLastOccluded) && !mLastDozing || mLastBouncerShowing
- || mLastRemoteInputActive;
+ return (!(mLastShowing && !mLastOccluded) && !mLastDozing || mLastBouncerShowing
+ || mLastRemoteInputActive) && !mLastDeferScrimFadeOut;
}
public boolean shouldDismissOnMenuPressed() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index df30e20ca582..9daa199ee92a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -37,6 +37,9 @@ public interface BluetoothController extends CallbackController<Callback>, Dumpa
void disconnect(CachedBluetoothDevice device);
boolean canConfigBluetooth();
+ int getMaxConnectionState(CachedBluetoothDevice device);
+ int getBondState(CachedBluetoothDevice device);
+
public interface Callback {
void onBluetoothStateChange(boolean enabled);
void onBluetoothDevicesChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 36d24b370b00..dc4b1158c1cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.policy;
import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
@@ -33,8 +35,10 @@ import com.android.systemui.Dependency;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.WeakHashMap;
public class BluetoothControllerImpl implements BluetoothController, BluetoothCallback,
CachedBluetoothDevice.Callback {
@@ -44,18 +48,22 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
private final LocalBluetoothManager mLocalBluetoothManager;
private final UserManager mUserManager;
private final int mCurrentUser;
+ private final WeakHashMap<CachedBluetoothDevice, ActuallyCachedState> mCachedState =
+ new WeakHashMap<>();
+ private final Handler mBgHandler;
private boolean mEnabled;
private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
private CachedBluetoothDevice mLastDevice;
- private final H mHandler = new H();
+ private final H mHandler = new H(Looper.getMainLooper());
private int mState;
public BluetoothControllerImpl(Context context, Looper bgLooper) {
mLocalBluetoothManager = Dependency.get(LocalBluetoothManager.class);
+ mBgHandler = new Handler(bgLooper);
if (mLocalBluetoothManager != null) {
- mLocalBluetoothManager.getEventManager().setReceiverHandler(new Handler(bgLooper));
+ mLocalBluetoothManager.getEventManager().setReceiverHandler(mBgHandler);
mLocalBluetoothManager.getEventManager().registerCallback(this);
onBluetoothStateChanged(
mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
@@ -106,6 +114,16 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
}
@Override
+ public int getBondState(CachedBluetoothDevice device) {
+ return getCachedState(device).mBondState;
+ }
+
+ @Override
+ public int getMaxConnectionState(CachedBluetoothDevice device) {
+ return getCachedState(device).mMaxConnectionState;
+ }
+
+ @Override
public void addCallback(Callback cb) {
mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
@@ -225,12 +243,14 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
@Override
public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
+ mCachedState.remove(cachedDevice);
updateConnected();
mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
}
@Override
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
+ mCachedState.remove(cachedDevice);
updateConnected();
mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
}
@@ -243,11 +263,44 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
@Override
public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
+ mCachedState.remove(cachedDevice);
mLastDevice = cachedDevice;
updateConnected();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
}
+ private ActuallyCachedState getCachedState(CachedBluetoothDevice device) {
+ ActuallyCachedState state = mCachedState.get(device);
+ if (state == null) {
+ state = new ActuallyCachedState(device, mHandler);
+ mBgHandler.post(state);
+ mCachedState.put(device, state);
+ return state;
+ }
+ return state;
+ }
+
+ private static class ActuallyCachedState implements Runnable {
+
+ private final WeakReference<CachedBluetoothDevice> mDevice;
+ private final Handler mUiHandler;
+ private int mBondState = BluetoothDevice.BOND_NONE;
+ private int mMaxConnectionState = BluetoothProfile.STATE_DISCONNECTED;
+
+ private ActuallyCachedState(CachedBluetoothDevice device, Handler uiHandler) {
+ mDevice = new WeakReference<>(device);
+ mUiHandler = uiHandler;
+ }
+
+ @Override
+ public void run() {
+ mBondState = mDevice.get().getBondState();
+ mMaxConnectionState = mDevice.get().getMaxConnectionState();
+ mUiHandler.removeMessages(H.MSG_PAIRED_DEVICES_CHANGED);
+ mUiHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
+ }
+ }
+
private final class H extends Handler {
private final ArrayList<BluetoothController.Callback> mCallbacks = new ArrayList<>();
@@ -256,6 +309,10 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
private static final int MSG_ADD_CALLBACK = 3;
private static final int MSG_REMOVE_CALLBACK = 4;
+ public H(Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
index 56c07f905446..23451106a20c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -28,6 +28,8 @@ class DozeHostFake implements DozeHost {
boolean pulseExtended;
boolean animateWakeup;
boolean dozing;
+ float doubleTapX;
+ float doubleTapY;
@Override
public void addCallback(@NonNull Callback callback) {
@@ -88,4 +90,10 @@ class DozeHostFake implements DozeHost {
public void setAnimateWakeup(boolean animateWakeup) {
this.animateWakeup = animateWakeup;
}
+
+ @Override
+ public void onDoubleTap(float x, float y) {
+ doubleTapX = y;
+ doubleTapY = y;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java
new file mode 100644
index 000000000000..aef584f8d986
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 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.qs;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.qs.QSTile.SlashState;
+import com.android.systemui.qs.tileimpl.SlashImageView;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class SlashImageViewTest extends SysuiTestCase {
+ private TestableSlashImageView mSlashView;
+
+ @Test
+ public void testSetSlashStateCreatesSlashDrawable() {
+ SlashState mockState = mock(SlashState.class);
+ Drawable mockDrawable = mock(Drawable.class);
+ mSlashView = new TestableSlashImageView(mContext);
+ assertTrue(mSlashView.getSlashDrawable() == null);
+
+ mSlashView.setImageDrawable(mockDrawable);
+ mSlashView.setState(mockState);
+
+ assertTrue(mSlashView.getSlashDrawable() != null);
+ }
+
+ @Test
+ public void testSetNullDrawableRemovesSlashDrawable() {
+ SlashState mockState = mock(SlashState.class);
+ Drawable mockDrawable = mock(Drawable.class);
+
+ mSlashView = new TestableSlashImageView(mContext);
+ mSlashView.setImageDrawable(mockDrawable);
+ mSlashView.setState(mockState);
+ mSlashView.setImageDrawable(null);
+
+ assertTrue(mSlashView.getSlashDrawable() == null);
+ }
+
+ // Expose getSlashDrawable
+ private static class TestableSlashImageView extends SlashImageView {
+ TestableSlashImageView(Context c) {
+ super(c);
+ }
+
+ private SlashDrawable getSlashDrawable() {
+ return mSlash;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index 2eb95603cef0..4cc8bcae541a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -14,16 +14,21 @@
package com.android.systemui.statusbar.policy;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
+import android.os.Looper;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import android.util.Log;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -80,4 +85,56 @@ public class BluetoothControllerImplTest extends SysuiTestCase {
BluetoothAdapter.STATE_DISCONNECTED);
assertTrue(mBluetoothControllerImpl.isBluetoothConnected());
}
+
+ @Test
+ public void testDefaultConnectionState() {
+ CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+ assertEquals(BluetoothDevice.BOND_NONE, mBluetoothControllerImpl.getBondState(device));
+ assertEquals(BluetoothProfile.STATE_DISCONNECTED,
+ mBluetoothControllerImpl.getMaxConnectionState(device));
+ }
+
+ @Test
+ public void testAsyncBondState() throws Exception {
+ CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+ when(device.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ BluetoothController.Callback callback = mock(BluetoothController.Callback.class);
+ mBluetoothControllerImpl.addCallback(callback);
+
+ // Grab the main looper, we'll need it later.
+ TestableLooper mainLooper = new TestableLooper(Looper.getMainLooper());
+
+ // Trigger the state getting.
+ assertEquals(BluetoothDevice.BOND_NONE, mBluetoothControllerImpl.getBondState(device));
+
+ mTestableLooper.processMessages(1);
+ mainLooper.processAllMessages();
+
+ assertEquals(BluetoothDevice.BOND_BONDED, mBluetoothControllerImpl.getBondState(device));
+ verify(callback).onBluetoothDevicesChanged();
+ mainLooper.destroy();
+ }
+
+ @Test
+ public void testAsyncConnectionState() throws Exception {
+ CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+ when(device.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_CONNECTED);
+ BluetoothController.Callback callback = mock(BluetoothController.Callback.class);
+ mBluetoothControllerImpl.addCallback(callback);
+
+ // Grab the main looper, we'll need it later.
+ TestableLooper mainLooper = new TestableLooper(Looper.getMainLooper());
+
+ // Trigger the state getting.
+ assertEquals(BluetoothProfile.STATE_DISCONNECTED,
+ mBluetoothControllerImpl.getMaxConnectionState(device));
+
+ mTestableLooper.processMessages(1);
+ mainLooper.processAllMessages();
+
+ assertEquals(BluetoothProfile.STATE_CONNECTED,
+ mBluetoothControllerImpl.getMaxConnectionState(device));
+ verify(callback).onBluetoothDevicesChanged();
+ mainLooper.destroy();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
index 0ba031908d90..9ec096ad49e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
@@ -83,4 +83,14 @@ public class FakeBluetoothController extends BaseLeakChecker<Callback> implement
public boolean canConfigBluetooth() {
return false;
}
+
+ @Override
+ public int getMaxConnectionState(CachedBluetoothDevice device) {
+ return 0;
+ }
+
+ @Override
+ public int getBondState(CachedBluetoothDevice device) {
+ return 0;
+ }
}
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 1a5ec61a1510..c8e6e2efb240 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -2445,6 +2445,28 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
+ @Override
+ public boolean isOperationActive(int code, int uid, String packageName) {
+ verifyIncomingUid(uid);
+ verifyIncomingOp(code);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return false;
+ }
+ synchronized (this) {
+ for (int i = mClients.size() - 1; i >= 0; i--) {
+ final ClientState client = mClients.valueAt(i);
+ if (client.mStartedOps == null) continue;
+
+ for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
+ final Op op = client.mStartedOps.get(j);
+ if (op.op == code && op.uid == uid) return true;
+ }
+ }
+ }
+ return false;
+ }
+
private void removeUidsForUserLocked(int userHandle) {
for (int i = mUidStates.size() - 1; i >= 0; --i) {
final int uid = mUidStates.keyAt(i);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 35b452a12e64..f718e803a973 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -90,14 +90,12 @@ import android.util.AtomicFile;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.os.AppFuseMount;
-import com.android.internal.os.FuseAppLoop;
import com.android.internal.os.FuseUnavailableMountException;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.Zygote;
@@ -143,7 +141,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
-import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -3291,20 +3288,41 @@ class StorageManagerService extends IStorageManager.Stub
}
}
- @Override
- public long getAllocatableBytes(String volumeUuid, int flags) {
- final StorageManager storage = mContext.getSystemService(StorageManager.class);
- final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
-
- // Apps can't defy reserved space
- flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_RESERVED;
-
- final boolean aggressive = (flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0;
- if (aggressive) {
+ private int adjustAllocateFlags(int flags, int callingUid, String callingPackage) {
+ // Require permission to allocate aggressively
+ if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ALLOCATE_AGGRESSIVE, TAG);
}
+ // Apps normally can't directly defy reserved space
+ flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED;
+ flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED;
+
+ // However, if app is actively using the camera, then we're willing to
+ // clear up to half of the reserved cache space, since the user might be
+ // trying to capture an important memory.
+ final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (appOps.isOperationActive(AppOpsManager.OP_CAMERA, callingUid, callingPackage)) {
+ Slog.d(TAG, "UID " + callingUid + " is actively using camera;"
+ + " letting them defy reserved cached data");
+ flags |= StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ return flags;
+ }
+
+ @Override
+ public long getAllocatableBytes(String volumeUuid, int flags, String callingPackage) {
+ flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
+
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
final long token = Binder.clearCallingIdentity();
try {
// In general, apps can allocate as much space as they want, except
@@ -3319,18 +3337,18 @@ class StorageManagerService extends IStorageManager.Stub
if (stats.isQuotaSupported(volumeUuid)) {
final long cacheTotal = stats.getCacheBytes(volumeUuid);
- final long cacheReserved = storage.getStorageCacheBytes(path);
+ final long cacheReserved = storage.getStorageCacheBytes(path, flags);
final long cacheClearable = Math.max(0, cacheTotal - cacheReserved);
- if (aggressive) {
- return Math.max(0, (usable + cacheTotal) - fullReserved);
+ if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
+ return Math.max(0, (usable + cacheClearable) - fullReserved);
} else {
return Math.max(0, (usable + cacheClearable) - lowReserved);
}
} else {
// When we don't have fast quota information, we ignore cached
// data and only consider unused bytes.
- if (aggressive) {
+ if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
return Math.max(0, usable - fullReserved);
} else {
return Math.max(0, usable - lowReserved);
@@ -3344,20 +3362,16 @@ class StorageManagerService extends IStorageManager.Stub
}
@Override
- public void allocateBytes(String volumeUuid, long bytes, int flags) {
- final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ public void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) {
+ flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
- // Apps can't defy reserved space
- flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_RESERVED;
-
- // This method call will enforce FLAG_ALLOCATE_AGGRESSIVE permissions so
- // we don't have to enforce them locally
- final long allocatableBytes = getAllocatableBytes(volumeUuid, flags);
+ final long allocatableBytes = getAllocatableBytes(volumeUuid, flags, callingPackage);
if (bytes > allocatableBytes) {
throw new ParcelableException(new IOException("Failed to allocate " + bytes
+ " because only " + allocatableBytes + " allocatable"));
}
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
final long token = Binder.clearCallingIdentity();
try {
// Free up enough disk space to satisfy both the requested allocation
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 76456f3edccc..ad442c714926 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1804,7 +1804,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
AppErrorResult res = (AppErrorResult) data.get("result");
if (mShowDialogs && !mSleeping && !mShuttingDown) {
- Dialog d = new StrictModeViolationDialog(mContext,
+ Dialog d = new StrictModeViolationDialog(mUiContext,
ActivityManagerService.this, res, proc);
d.show();
proc.crashDialog = d;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ba8fa31dc46c..f720cd51cd86 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -600,6 +600,7 @@ final class UserController {
void finishUserStopping(final int userId, final UserState uss) {
// On to the next.
final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
+ shutdownIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
// This is the result receiver for the final shutdown broadcast.
final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
@Override
diff --git a/services/core/java/com/android/server/job/GrantedUriPermissions.java b/services/core/java/com/android/server/job/GrantedUriPermissions.java
index e413d8d1d8c0..c23b109bb9de 100644
--- a/services/core/java/com/android/server/job/GrantedUriPermissions.java
+++ b/services/core/java/com/android/server/job/GrantedUriPermissions.java
@@ -29,7 +29,7 @@ import android.util.Slog;
import java.io.PrintWriter;
import java.util.ArrayList;
-public class GrantedUriPermissions {
+public final class GrantedUriPermissions {
private final int mGrantFlags;
private final int mSourceUserId;
private final String mTag;
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
index 2d2f61f0288d..a53c0885f334 100644
--- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -26,7 +26,7 @@ import android.os.UserHandle;
import java.io.PrintWriter;
-public class JobSchedulerShellCommand extends ShellCommand {
+public final class JobSchedulerShellCommand extends ShellCommand {
public static final int CMD_ERR_NO_PACKAGE = -1000;
public static final int CMD_ERR_NO_JOB = -1001;
public static final int CMD_ERR_CONSTRAINTS = -1002;
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 637db11af6d8..5d3f6f7b804b 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -55,13 +55,13 @@ import com.android.server.job.controllers.JobStatus;
* job lands, and again when it is complete.
* - Cancelling is trickier, because there are also interactions from the client. It's possible
* the {@link com.android.server.job.JobServiceContext.JobServiceHandler} tries to process a
- * {@link #doCancelLocked(int)} after the client has already finished. This is handled by having
+ * {@link #doCancelLocked} after the client has already finished. This is handled by having
* {@link com.android.server.job.JobServiceContext.JobServiceHandler#handleCancelLocked} check whether
* the context is still valid.
* To mitigate this, we avoid sending duplicate onStopJob()
* calls to the client after they've specified jobFinished().
*/
-public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection {
+public final class JobServiceContext implements ServiceConnection {
private static final boolean DEBUG = JobSchedulerService.DEBUG;
private static final String TAG = "JobServiceContext";
/** Amount of time a job is allowed to execute for before being considered timed-out. */
@@ -112,6 +112,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
* Writes can only be done from the handler thread, or {@link #executeRunnableJob(JobStatus)}.
*/
private JobStatus mRunningJob;
+ private JobCallback mRunningCallback;
/** Used to store next job to run when current job is to be preempted. */
private int mPreferredUid;
IJobService service;
@@ -133,6 +134,36 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
// Debugging: time this job was last stopped.
public long mStoppedTime;
+ final class JobCallback extends IJobCallback.Stub {
+ public String mStoppedReason;
+ public long mStoppedTime;
+
+ @Override
+ public void acknowledgeStartMessage(int jobId, boolean ongoing) {
+ doAcknowledgeStartMessage(this, jobId, ongoing);
+ }
+
+ @Override
+ public void acknowledgeStopMessage(int jobId, boolean reschedule) {
+ doAcknowledgeStopMessage(this, jobId, reschedule);
+ }
+
+ @Override
+ public JobWorkItem dequeueWork(int jobId) {
+ return doDequeueWork(this, jobId);
+ }
+
+ @Override
+ public boolean completeWork(int jobId, int workId) {
+ return doCompleteWork(this, jobId, workId);
+ }
+
+ @Override
+ public void jobFinished(int jobId, boolean reschedule) {
+ doJobFinished(this, jobId, reschedule);
+ }
+ }
+
JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats,
JobPackageTracker tracker, Looper looper) {
this(service.getContext(), service.getLock(), batteryStats, tracker, service, looper);
@@ -168,6 +199,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
mPreferredUid = NO_PREFERRED_UID;
mRunningJob = job;
+ mRunningCallback = new JobCallback();
final boolean isDeadlineExpired =
job.hasDeadlineConstraint() &&
(job.getLatestRunTimeElapsed() < SystemClock.elapsedRealtime());
@@ -182,7 +214,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
job.changedAuthorities.toArray(triggeredAuthorities);
}
final JobInfo ji = job.getJob();
- mParams = new JobParameters(this, job.getJobId(), ji.getExtras(),
+ mParams = new JobParameters(mRunningCallback, job.getJobId(), ji.getExtras(),
ji.getTransientExtras(), ji.getClipData(), ji.getClipGrantFlags(),
isDeadlineExpired, triggeredUris, triggeredAuthorities);
mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();
@@ -198,6 +230,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
Slog.d(TAG, job.getServiceComponent().getShortClassName() + " unavailable.");
}
mRunningJob = null;
+ mRunningCallback = null;
mParams = null;
mExecutionStartTimeElapsed = 0L;
mVerb = VERB_FINISHED;
@@ -263,28 +296,29 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
return false;
}
- @Override
- public void jobFinished(int jobId, boolean reschedule) {
- doCallback(reschedule, "app called jobFinished");
+ void doJobFinished(JobCallback cb, int jobId, boolean reschedule) {
+ doCallback(cb, reschedule, "app called jobFinished");
}
- @Override
- public void acknowledgeStopMessage(int jobId, boolean reschedule) {
- doCallback(reschedule, null);
+ void doAcknowledgeStopMessage(JobCallback cb, int jobId, boolean reschedule) {
+ doCallback(cb, reschedule, null);
}
- @Override
- public void acknowledgeStartMessage(int jobId, boolean ongoing) {
- doCallback(ongoing, "finished start");
+ void doAcknowledgeStartMessage(JobCallback cb, int jobId, boolean ongoing) {
+ doCallback(cb, ongoing, "finished start");
}
- @Override
- public JobWorkItem dequeueWork(int jobId) {
- final int callingUid = Binder.getCallingUid();
+ JobWorkItem doDequeueWork(JobCallback cb, int jobId) {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- assertCallingUidLocked(callingUid);
+ assertCallerLocked(cb);
+ if (mVerb == VERB_STOPPING || mVerb == VERB_FINISHED) {
+ // This job is either all done, or on its way out. Either way, it
+ // should not dispatch any more work. We will pick up any remaining
+ // work the next time we start the job again.
+ return null;
+ }
final JobWorkItem work = mRunningJob.dequeueWorkLocked();
if (work == null && !mRunningJob.hasExecutingWorkLocked()) {
// This will finish the job.
@@ -297,13 +331,11 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
}
}
- @Override
- public boolean completeWork(int jobId, int workId) {
- final int callingUid = Binder.getCallingUid();
+ boolean doCompleteWork(JobCallback cb, int jobId, int workId) {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- assertCallingUidLocked(callingUid);
+ assertCallerLocked(cb);
return mRunningJob.completeWorkLocked(ActivityManager.getService(), workId);
}
} finally {
@@ -369,8 +401,8 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
* whether the client exercising the callback is the client we expect.
* @return True if the binder calling is coming from the client we expect.
*/
- private boolean verifyCallingUidLocked(final int callingUid) {
- if (mRunningJob == null || callingUid != mRunningJob.getUid()) {
+ private boolean verifyCallerLocked(JobCallback cb) {
+ if (mRunningCallback != cb) {
if (DEBUG) {
Slog.d(TAG, "Stale callback received, ignoring.");
}
@@ -379,16 +411,15 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
return true;
}
- private void assertCallingUidLocked(final int callingUid) {
- if (!verifyCallingUidLocked(callingUid)) {
+ private void assertCallerLocked(JobCallback cb) {
+ if (!verifyCallerLocked(cb)) {
StringBuilder sb = new StringBuilder(128);
- sb.append("Bad calling uid ");
- sb.append(callingUid);
- if (mStoppedReason != null) {
+ sb.append("Caller no longer running");
+ if (cb.mStoppedReason != null) {
sb.append(", last stopped ");
- TimeUtils.formatDuration(SystemClock.elapsedRealtime() - mStoppedTime, sb);
+ TimeUtils.formatDuration(SystemClock.elapsedRealtime() - cb.mStoppedTime, sb);
sb.append(" because: ");
- sb.append(mStoppedReason);
+ sb.append(cb.mStoppedReason);
}
throw new SecurityException(sb.toString());
}
@@ -421,12 +452,11 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
handleServiceBoundLocked();
}
- void doCallback(boolean reschedule, String reason) {
- final int callingUid = Binder.getCallingUid();
+ void doCallback(JobCallback cb, boolean reschedule, String reason) {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- if (!verifyCallingUidLocked(callingUid)) {
+ if (!verifyCallerLocked(cb)) {
return;
}
doCallbackLocked(reschedule, reason);
@@ -559,7 +589,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
* VERB_BINDING -> Cancelled before bind completed. Mark as cancelled and wait for
* {@link #onServiceConnected(android.content.ComponentName, android.os.IBinder)}
* _STARTING -> Mark as cancelled and wait for
- * {@link JobServiceContext#acknowledgeStartMessage(int, boolean)}
+ * {@link JobServiceContext#doAcknowledgeStartMessage}
* _EXECUTING -> call {@link #sendStopMessageLocked}}, but only if there are no callbacks
* in the message queue.
* _ENDING -> No point in doing anything here, so we ignore.
@@ -671,6 +701,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
mContext.unbindService(JobServiceContext.this);
mWakeLock = null;
mRunningJob = null;
+ mRunningCallback = null;
mParams = null;
mVerb = VERB_FINISHED;
mCancelled = false;
@@ -684,6 +715,10 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
if (reason != null && mStoppedReason == null) {
mStoppedReason = reason;
mStoppedTime = SystemClock.elapsedRealtime();
+ if (mRunningCallback != null) {
+ mRunningCallback.mStoppedReason = mStoppedReason;
+ mRunningCallback.mStoppedTime = mStoppedTime;
+ }
}
}
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 22eed3b04250..f0cd8a8569e0 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -66,7 +66,7 @@ import org.xmlpull.v1.XmlSerializer;
* and {@link com.android.server.job.JobStore.ReadJobMapFromDiskRunnable} lock on that
* object.
*/
-public class JobStore {
+public final class JobStore {
private static final String TAG = "JobStore";
private static final boolean DEBUG = JobSchedulerService.DEBUG;
@@ -263,7 +263,7 @@ public class JobStore {
* Runnable that writes {@link #mJobSet} out to xml.
* NOTE: This Runnable locks on mLock
*/
- private class WriteJobsMapToDiskRunnable implements Runnable {
+ private final class WriteJobsMapToDiskRunnable implements Runnable {
@Override
public void run() {
final long startElapsed = SystemClock.elapsedRealtime();
@@ -444,7 +444,7 @@ public class JobStore {
* Runnable that reads list of persisted job from xml. This is run once at start up, so doesn't
* need to go through {@link JobStore#add(com.android.server.job.controllers.JobStatus)}.
*/
- private class ReadJobMapFromDiskRunnable implements Runnable {
+ private final class ReadJobMapFromDiskRunnable implements Runnable {
private final JobSet jobSet;
/**
@@ -796,7 +796,7 @@ public class JobStore {
}
}
- static class JobSet {
+ static final class JobSet {
// Key is the getUid() originator of the jobs in each sheaf
private SparseArray<ArraySet<JobStatus>> mJobs;
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index 68dd00ff00c1..39f2a96b30e3 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -33,7 +33,7 @@ import java.io.PrintWriter;
* for a certain amount of time (maybe hours or days) are considered idle. When the app comes
* out of idle state, it will be allowed to run scheduled jobs.
*/
-public class AppIdleController extends StateController {
+public final class AppIdleController extends StateController {
private static final String LOG_TAG = "AppIdleController";
private static final boolean DEBUG = false;
@@ -171,7 +171,7 @@ public class AppIdleController extends StateController {
}
}
- private class AppIdleStateChangeListener
+ private final class AppIdleStateChangeListener
extends UsageStatsManagerInternal.AppIdleStateChangeListener {
@Override
public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index d275bd94a6f4..91119690617a 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -39,7 +39,7 @@ import java.io.PrintWriter;
* be charging when it's been plugged in for more than two minutes, and the system has broadcast
* ACTION_BATTERY_OK.
*/
-public class BatteryController extends StateController {
+public final class BatteryController extends StateController {
private static final String TAG = "JobScheduler.Batt";
private static final Object sCreationLock = new Object();
@@ -121,7 +121,7 @@ public class BatteryController extends StateController {
}
}
- public class ChargingTracker extends BroadcastReceiver {
+ public final class ChargingTracker extends BroadcastReceiver {
/**
* Track whether we're "charging", where charging means that we're ready to commit to
* doing work.
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index f4268185aa40..17c89282f280 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -43,7 +43,7 @@ import java.io.PrintWriter;
* status due to user-requested network policies, so we need to check
* constraints on a per-UID basis.
*/
-public class ConnectivityController extends StateController implements
+public final class ConnectivityController extends StateController implements
ConnectivityManager.OnNetworkActiveListener {
private static final String TAG = "JobScheduler.Conn";
private static final boolean DEBUG = false;
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
index cfafc38428f3..ff807eccee7b 100644
--- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
@@ -39,7 +39,7 @@ import java.util.ArrayList;
/**
* Controller for monitoring changes to content URIs through a ContentObserver.
*/
-public class ContentObserverController extends StateController {
+public final class ContentObserverController extends StateController {
private static final String TAG = "JobScheduler.Content";
private static final boolean DEBUG = false;
diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 5ccf81288255..85993b900dc9 100644
--- a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -37,7 +37,7 @@ import java.util.Arrays;
* When device is dozing, set constraint for all jobs, except whitelisted apps, as not satisfied.
* When device is not dozing, set constraint for all jobs as satisfied.
*/
-public class DeviceIdleJobsController extends StateController {
+public final class DeviceIdleJobsController extends StateController {
private static final String LOG_TAG = "DeviceIdleJobsController";
private static final boolean LOG_DEBUG = false;
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index 7e922930e6e8..9eda046fa1e4 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -33,7 +33,7 @@ import com.android.server.am.ActivityManagerService;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateChangedListener;
-public class IdleController extends StateController {
+public final class IdleController extends StateController {
private static final String TAG = "IdleController";
// Policy: we decide that we're "idle" if the device has been unused /
@@ -107,7 +107,7 @@ public class IdleController extends StateController {
mIdleTracker.startTracking();
}
- class IdlenessTracker extends BroadcastReceiver {
+ final class IdlenessTracker extends BroadcastReceiver {
private AlarmManager mAlarm;
private PendingIntent mIdleTriggerIntent;
boolean mIdle;
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 53bf40245819..446b0d67ce95 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -698,7 +698,8 @@ public final class JobStatus {
static final int CONSTRAINTS_OF_INTEREST =
CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW |
CONSTRAINT_TIMING_DELAY |
- CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED | CONSTRAINT_NOT_ROAMING |
+ CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
+ CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED |
CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
// Soft override covers all non-"functional" constraints
@@ -865,6 +866,9 @@ public final class JobStatus {
if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) {
pw.print(" NOT_ROAMING");
}
+ if ((constraints&CONSTRAINT_METERED) != 0) {
+ pw.print(" METERED");
+ }
if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
pw.print(" APP_NOT_IDLE");
}
diff --git a/services/core/java/com/android/server/job/controllers/StorageController.java b/services/core/java/com/android/server/job/controllers/StorageController.java
index 4fe8eca54a6e..c24e563948d4 100644
--- a/services/core/java/com/android/server/job/controllers/StorageController.java
+++ b/services/core/java/com/android/server/job/controllers/StorageController.java
@@ -35,7 +35,7 @@ import java.io.PrintWriter;
/**
* Simple controller that tracks the status of the device's storage.
*/
-public class StorageController extends StateController {
+public final class StorageController extends StateController {
private static final String TAG = "JobScheduler.Stor";
private static final Object sCreationLock = new Object();
@@ -112,7 +112,7 @@ public class StorageController extends StateController {
}
}
- public class StorageTracker extends BroadcastReceiver {
+ public final class StorageTracker extends BroadcastReceiver {
/**
* Track whether storage is low.
*/
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index 01c841e2083c..d90699a61928 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -38,7 +38,7 @@ import java.util.ListIterator;
* This class sets an alarm for the next expiring job, and determines whether a job's minimum
* delay has been satisfied.
*/
-public class TimeController extends StateController {
+public final class TimeController extends StateController {
private static final String TAG = "JobScheduler.Time";
/** Deadline alarm tag for logging purposes */
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index 34cc6e37d996..d0d306c580ba 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -121,8 +121,11 @@ public abstract class InstantAppResolver {
resolutionStatus = RESOLUTION_FAILURE;
}
}
- logMetrics(ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE, startTime, token,
- resolutionStatus);
+ // Only log successful instant application resolution
+ if (resolutionStatus == RESOLUTION_SUCCESS) {
+ logMetrics(ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE, startTime, token,
+ resolutionStatus);
+ }
if (DEBUG_EPHEMERAL && resolveInfo == null) {
if (resolutionStatus == RESOLUTION_BIND_TIMEOUT) {
Log.d(TAG, "[" + token + "] Phase1; bind timed out");
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 6f07973962bb..bf64f6427c7c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -81,8 +81,10 @@ import android.util.ExceptionUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.util.Xml;
+import java.io.CharArrayWriter;
import libcore.io.IoUtils;
import com.android.internal.R;
@@ -195,7 +197,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
/** Historical sessions kept around for debugging purposes */
@GuardedBy("mSessions")
- private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>();
+ private final List<String> mHistoricalSessions = new ArrayList<>();
+
+ @GuardedBy("mSessions")
+ private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray();
/** Sessions allocated to legacy users */
@GuardedBy("mSessions")
@@ -371,7 +376,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
// Since this is early during boot we don't send
// any observer events about the session, but we
// keep details around for dumpsys.
- mHistoricalSessions.put(session.sessionId, session);
+ addHistoricalSessionLocked(session);
}
mAllocatedSessions.put(session.sessionId, true);
}
@@ -386,6 +391,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
}
+ private void addHistoricalSessionLocked(PackageInstallerSession session) {
+ CharArrayWriter writer = new CharArrayWriter();
+ IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ session.dump(pw);
+ mHistoricalSessions.add(writer.toString());
+
+ // Increment the number of sessions by this installerUid.
+ mHistoricalSessionsByInstaller.put(
+ session.installerUid,
+ mHistoricalSessionsByInstaller.get(session.installerUid) + 1);
+ }
+
private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException,
XmlPullParserException {
final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
@@ -676,7 +693,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
throw new IllegalStateException(
"Too many active sessions for UID " + callingUid);
}
- final int historicalCount = getSessionCount(mHistoricalSessions, callingUid);
+ final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
throw new IllegalStateException(
"Too many historical sessions for UID " + callingUid);
@@ -1228,8 +1245,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
pw.increaseIndent();
N = mHistoricalSessions.size();
for (int i = 0; i < N; i++) {
- final PackageInstallerSession session = mHistoricalSessions.valueAt(i);
- session.dump(pw);
+ pw.print(mHistoricalSessions.get(i));
pw.println();
}
pw.println();
@@ -1264,7 +1280,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
public void run() {
synchronized (mSessions) {
mSessions.remove(session.sessionId);
- mHistoricalSessions.put(session.sessionId, session);
+ addHistoricalSessionLocked(session);
final File appIconFile = buildAppIconFile(session.sessionId);
if (appIconFile.exists()) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 48b9c7de650b..bf3e5d37e7ae 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -49,6 +49,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_L
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
import static android.content.pm.PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
@@ -677,13 +678,6 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mPackages")
final SparseIntArray mIsolatedOwners = new SparseIntArray();
- // List of APK paths to load for each user and package. This data is never
- // persisted by the package manager. Instead, the overlay manager will
- // ensure the data is up-to-date in runtime.
- @GuardedBy("mPackages")
- final SparseArray<ArrayMap<String, ArrayList<String>>> mEnabledOverlayPaths =
- new SparseArray<ArrayMap<String, ArrayList<String>>>();
-
/**
* Tracks new system packages [received in an OTA] that we expect to
* find updated user-installed versions. Keys are package name, values
@@ -3584,8 +3578,6 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- rebaseEnabledOverlays(packageInfo.applicationInfo, userId);
-
packageInfo.packageName = packageInfo.applicationInfo.packageName =
resolveExternalPackageNameLPr(p);
@@ -4097,7 +4089,6 @@ public class PackageManagerService extends IPackageManager.Stub
ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags,
ps.readUserState(userId), userId);
if (ai != null) {
- rebaseEnabledOverlays(ai, userId);
ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
}
return ai;
@@ -4146,7 +4137,6 @@ public class PackageManagerService extends IPackageManager.Stub
ApplicationInfo ai = PackageParser.generateApplicationInfo(
p, flags, ps.readUserState(userId), userId);
if (ai != null) {
- rebaseEnabledOverlays(ai, userId);
ai.packageName = resolveExternalPackageNameLPr(p);
}
return ai;
@@ -4163,26 +4153,6 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- private void rebaseEnabledOverlays(@NonNull ApplicationInfo ai, int userId) {
- List<String> paths = new ArrayList<>();
- ArrayMap<String, ArrayList<String>> userSpecificOverlays =
- mEnabledOverlayPaths.get(userId);
- if (userSpecificOverlays != null) {
- if (!"android".equals(ai.packageName)) {
- ArrayList<String> frameworkOverlays = userSpecificOverlays.get("android");
- if (frameworkOverlays != null) {
- paths.addAll(frameworkOverlays);
- }
- }
-
- ArrayList<String> appOverlays = userSpecificOverlays.get(ai.packageName);
- if (appOverlays != null) {
- paths.addAll(appOverlays);
- }
- }
- ai.resourceDirs = paths.size() > 0 ? paths.toArray(new String[paths.size()]) : null;
- }
-
private String normalizePackageNameLPr(String packageName) {
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
return normalizedPackageName != null ? normalizedPackageName : packageName;
@@ -4258,10 +4228,7 @@ public class PackageManagerService extends IPackageManager.Stub
volumeUuid);
final boolean aggressive = (storageFlags
& StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0;
- final boolean defyReserved = (storageFlags
- & StorageManager.FLAG_ALLOCATE_DEFY_RESERVED) != 0;
- final long reservedBytes = (aggressive || defyReserved) ? 0
- : storage.getStorageCacheBytes(file);
+ final long reservedBytes = storage.getStorageCacheBytes(file, storageFlags);
// 1. Pre-flight to determine if we have any chance to succeed
// 2. Consider preloaded data (after 1w honeymoon, unless aggressive)
@@ -4567,24 +4534,6 @@ public class PackageManagerService extends IPackageManager.Stub
return updateFlagsForComponent(flags, userId, intent /*cookie*/);
}
- private ActivityInfo generateActivityInfo(ActivityInfo ai, int flags, PackageUserState state,
- int userId) {
- ActivityInfo ret = PackageParser.generateActivityInfo(ai, flags, state, userId);
- if (ret != null) {
- rebaseEnabledOverlays(ret.applicationInfo, userId);
- }
- return ret;
- }
-
- private ActivityInfo generateActivityInfo(PackageParser.Activity a, int flags,
- PackageUserState state, int userId) {
- ActivityInfo ai = PackageParser.generateActivityInfo(a, flags, state, userId);
- if (ai != null) {
- rebaseEnabledOverlays(ai.applicationInfo, userId);
- }
- return ai;
- }
-
@Override
public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId);
@@ -4612,11 +4561,12 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterAppAccessLPr(ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
return null;
}
- return generateActivityInfo(a, flags, ps.readUserState(userId), userId);
+ return PackageParser.generateActivityInfo(
+ a, flags, ps.readUserState(userId), userId);
}
if (mResolveComponentName.equals(component)) {
- return generateActivityInfo(mResolveActivity, flags, new PackageUserState(),
- userId);
+ return PackageParser.generateActivityInfo(
+ mResolveActivity, flags, new PackageUserState(), userId);
}
}
return null;
@@ -4670,7 +4620,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterAppAccessLPr(ps, callingUid, component, TYPE_RECEIVER, userId)) {
return null;
}
- return generateActivityInfo(a, flags, ps.readUserState(userId), userId);
+ return PackageParser.generateActivityInfo(
+ a, flags, ps.readUserState(userId), userId);
}
}
return null;
@@ -4806,12 +4757,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterAppAccessLPr(ps, callingUid, component, TYPE_SERVICE, userId)) {
return null;
}
- ServiceInfo si = PackageParser.generateServiceInfo(s, flags,
- ps.readUserState(userId), userId);
- if (si != null) {
- rebaseEnabledOverlays(si.applicationInfo, userId);
- }
- return si;
+ return PackageParser.generateServiceInfo(
+ s, flags, ps.readUserState(userId), userId);
}
}
return null;
@@ -4834,12 +4781,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
return null;
}
- ProviderInfo pi = PackageParser.generateProviderInfo(p, flags,
- ps.readUserState(userId), userId);
- if (pi != null) {
- rebaseEnabledOverlays(pi.applicationInfo, userId);
- }
- return pi;
+ return PackageParser.generateProviderInfo(
+ p, flags, ps.readUserState(userId), userId);
}
}
return null;
@@ -8265,7 +8208,6 @@ public class PackageManagerService extends IPackageManager.Stub
ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
ps.readUserState(userId), userId);
if (ai != null) {
- rebaseEnabledOverlays(ai, userId);
ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
}
} else {
@@ -8292,7 +8234,6 @@ public class PackageManagerService extends IPackageManager.Stub
ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
ps.readUserState(userId), userId);
if (ai != null) {
- rebaseEnabledOverlays(ai, userId);
ai.packageName = resolveExternalPackageNameLPr(p);
list.add(ai);
}
@@ -8446,7 +8387,6 @@ public class PackageManagerService extends IPackageManager.Stub
ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
ps.readUserState(userId), userId);
if (ai != null) {
- rebaseEnabledOverlays(ai, userId);
finalList.add(ai);
}
}
@@ -13370,7 +13310,8 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
final PackageUserState userState = ps.readUserState(userId);
- ActivityInfo ai = generateActivityInfo(activity, mFlags, userState, userId);
+ ActivityInfo ai =
+ PackageParser.generateActivityInfo(activity, mFlags, userState, userId);
if (ai == null) {
return null;
}
@@ -17899,16 +17840,17 @@ public class PackageManagerService extends IPackageManager.Stub
// Instant apps must have target SDK >= O and have targetSanboxVersion >= 2
if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
- Slog.w(TAG, "Instant app package " + pkg.packageName
- + " does not target O, this will be a fatal error.");
- // STOPSHIP: Make this a fatal error
- pkg.applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
+ Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O");
+ res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
+ "Instant app package must target O");
+ return;
}
if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) {
Slog.w(TAG, "Instant app package " + pkg.packageName
- + " does not target targetSandboxVersion 2, this will be a fatal error.");
- // STOPSHIP: Make this a fatal error
- pkg.applicationInfo.targetSandboxVersion = 2;
+ + " does not target targetSandboxVersion 2");
+ res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
+ "Instant app package must use targetSanboxVersion 2");
+ return;
}
if (pkg.applicationInfo.isStaticSharedLibrary()) {
@@ -22349,11 +22291,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
dumpCompilerStatsLPr(pw, packageName);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_ENABLED_OVERLAYS)) {
- if (dumpState.onTitlePrinted()) pw.println();
- dumpEnabledOverlaysLPr(pw);
- }
-
if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
if (dumpState.onTitlePrinted()) pw.println();
mSettings.dumpReadMessagesLPr(pw, dumpState);
@@ -22550,23 +22487,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
}
- private void dumpEnabledOverlaysLPr(PrintWriter pw) {
- pw.println("Enabled overlay paths:");
- final int N = mEnabledOverlayPaths.size();
- for (int i = 0; i < N; i++) {
- final int userId = mEnabledOverlayPaths.keyAt(i);
- pw.println(String.format(" User %d:", userId));
- final ArrayMap<String, ArrayList<String>> userSpecificOverlays =
- mEnabledOverlayPaths.valueAt(i);
- final int M = userSpecificOverlays.size();
- for (int j = 0; j < M; j++) {
- final String targetPackageName = userSpecificOverlays.keyAt(j);
- final ArrayList<String> overlayPackagePaths = userSpecificOverlays.valueAt(j);
- pw.println(String.format(" %s: %s", targetPackageName, overlayPackagePaths));
- }
- }
- }
-
private String dumpDomainString(String packageName) {
List<IntentFilterVerificationInfo> iviList = getIntentFilterVerifications(packageName)
.getList();
@@ -24744,11 +24664,10 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
Slog.e(TAG, "failed to find package " + targetPackageName);
return false;
}
-
- ArrayList<String> paths = null;
- if (overlayPackageNames != null) {
+ ArrayList<String> overlayPaths = null;
+ if (overlayPackageNames != null && overlayPackageNames.size() > 0) {
final int N = overlayPackageNames.size();
- paths = new ArrayList<>(N);
+ overlayPaths = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
final String packageName = overlayPackageNames.get(i);
final PackageParser.Package pkg = mPackages.get(packageName);
@@ -24756,22 +24675,17 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
Slog.e(TAG, "failed to find package " + packageName);
return false;
}
- paths.add(pkg.baseCodePath);
+ overlayPaths.add(pkg.baseCodePath);
}
}
- ArrayMap<String, ArrayList<String>> userSpecificOverlays =
- mEnabledOverlayPaths.get(userId);
- if (userSpecificOverlays == null) {
- userSpecificOverlays = new ArrayMap<>();
- mEnabledOverlayPaths.put(userId, userSpecificOverlays);
- }
-
- if (paths != null && paths.size() > 0) {
- userSpecificOverlays.put(targetPackageName, paths);
- } else {
- userSpecificOverlays.remove(targetPackageName);
+ final PackageSetting ps = mSettings.mPackages.get(targetPackageName);
+ String[] frameworkOverlayPaths = null;
+ if (!"android".equals(targetPackageName)) {
+ frameworkOverlayPaths =
+ mSettings.mPackages.get("android").getOverlayPaths(userId);
}
+ ps.setOverlayPaths(overlayPaths, frameworkOverlayPaths, userId);
return true;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 14f65eb485f4..d17267f38648 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -31,6 +31,7 @@ import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
+import com.google.android.collect.Lists;
import java.io.File;
import java.util.ArrayList;
@@ -329,6 +330,27 @@ abstract class PackageSettingBase extends SettingBase {
modifyUserState(userId).installReason = installReason;
}
+ void setOverlayPaths(List<String> overlayPaths, String[] frameworkOverlayPaths, int userId) {
+ if (overlayPaths == null && frameworkOverlayPaths == null) {
+ modifyUserState(userId).overlayPaths = null;
+ return;
+ }
+ final List<String> paths;
+ if (frameworkOverlayPaths == null) {
+ paths = overlayPaths;
+ } else {
+ paths = Lists.newArrayList(frameworkOverlayPaths);
+ if (overlayPaths != null) {
+ paths.addAll(overlayPaths);
+ }
+ }
+ modifyUserState(userId).overlayPaths = paths.toArray(new String[paths.size()]);
+ }
+
+ String[] getOverlayPaths(int userId) {
+ return readUserState(userId).overlayPaths;
+ }
+
/** Only use for testing. Do NOT use in production code. */
@VisibleForTesting
SparseArray<PackageUserState> getUserState() {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 24cbdbff9153..b006c2d991e6 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4858,6 +4858,15 @@ final class Settings {
pw.print(ps.getEnabled(user.id));
pw.print(" instant=");
pw.println(ps.getInstantApp(user.id));
+
+ String[] overlayPaths = ps.getOverlayPaths(user.id);
+ if (overlayPaths != null && overlayPaths.length > 0) {
+ pw.println("Overlay paths:");
+ for (String path : overlayPaths) {
+ pw.println(path);
+ }
+ }
+
String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
if (lastDisabledAppCaller != null) {
pw.print(prefix); pw.print(" lastDisabledCaller: ");
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4bc3725fecab..126e3ec30289 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3052,13 +3052,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
+ ": transit=" + transit);
if (win == mStatusBar) {
- boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+ final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+ final boolean expanded = win.getAttrs().height == MATCH_PARENT
+ && win.getAttrs().width == MATCH_PARENT;
+ if (isKeyguard || expanded) {
+ return -1;
+ }
if (transit == TRANSIT_EXIT
|| transit == TRANSIT_HIDE) {
- return isKeyguard ? -1 : R.anim.dock_top_exit;
+ return R.anim.dock_top_exit;
} else if (transit == TRANSIT_ENTER
|| transit == TRANSIT_SHOW) {
- return isKeyguard ? -1 : R.anim.dock_top_enter;
+ return R.anim.dock_top_enter;
}
} else if (win == mNavigationBar) {
if (win.getAttrs().windowAnimations != 0) {
@@ -6793,7 +6798,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public boolean isScreenOn() {
- return mScreenOnFully;
+ synchronized (mLock) {
+ return mScreenOnEarly;
+ }
}
/** {@inheritDoc} */
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 864e83ef1f86..02f2afcb0be8 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -256,7 +256,7 @@ public final class ShutdownThread extends Thread {
ProgressDialog pd = new ProgressDialog(context);
// Path 1: Reboot to recovery for update
- // Condition: mReason == REBOOT_RECOVERY_UPDATE
+ // Condition: mReason startswith REBOOT_RECOVERY_UPDATE
//
// Path 1a: uncrypt needed
// Condition: if /cache/recovery/uncrypt_file exists but
@@ -276,7 +276,9 @@ public final class ShutdownThread extends Thread {
// Path 3: Regular reboot / shutdown
// Condition: Otherwise
// UI: spinning circle only (no progress bar)
- if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) {
+
+ // mReason could be "recovery-update" or "recovery-update,quiescent".
+ if (mReason != null && mReason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
// We need the progress bar if uncrypt will be invoked during the
// reboot, which might be time-consuming.
mRebootHasProgressBar = RecoverySystem.UNCRYPT_PACKAGE_FILE.exists()
@@ -295,7 +297,7 @@ public final class ShutdownThread extends Thread {
pd.setMessage(context.getText(
com.android.internal.R.string.reboot_to_update_reboot));
}
- } else if (PowerManager.REBOOT_RECOVERY.equals(mReason)) {
+ } else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) {
// Factory reset path. Set the dialog message accordingly.
pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
pd.setMessage(context.getText(
@@ -389,7 +391,8 @@ public final class ShutdownThread extends Thread {
// First send the high-level shut down broadcast.
mActionDone = false;
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mContext.sendOrderedBroadcastAsUser(intent,
UserHandle.ALL, null, br, mHandler, 0, null, null);
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 410efcdb5038..cff2fadd7649 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -20,6 +20,8 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.animation.AnimationHandler;
+import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
@@ -30,11 +32,13 @@ import android.os.IBinder;
import android.os.Debug;
import android.util.ArrayMap;
import android.util.Slog;
+import android.view.Choreographer;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.WindowManagerInternal;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -49,7 +53,7 @@ import java.lang.annotation.RetentionPolicy;
*
* The object that is resized needs to implement {@link BoundsAnimationTarget} interface.
*
- * NOTE: All calls to methods in this class should be done on the UI thread
+ * NOTE: All calls to methods in this class should be done on the Animation thread
*/
public class BoundsAnimationController {
private static final boolean DEBUG_LOCAL = false;
@@ -111,20 +115,24 @@ public class BoundsAnimationController {
private final AppTransitionNotifier mAppTransitionNotifier = new AppTransitionNotifier();
private final Interpolator mFastOutSlowInInterpolator;
private boolean mFinishAnimationAfterTransition = false;
+ private final AnimationHandler mAnimationHandler;
private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000;
- BoundsAnimationController(Context context, AppTransition transition, Handler handler) {
+ BoundsAnimationController(Context context, AppTransition transition, Handler handler,
+ AnimationHandler animationHandler) {
mHandler = handler;
mAppTransition = transition;
mAppTransition.registerListenerLocked(mAppTransitionNotifier);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.fast_out_slow_in);
+ mAnimationHandler = animationHandler;
}
@VisibleForTesting
final class BoundsAnimator extends ValueAnimator
implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
+
private final BoundsAnimationTarget mTarget;
private final Rect mFrom = new Rect();
private final Rect mTo = new Rect();
@@ -198,6 +206,10 @@ public class BoundsAnimationController {
mTmpRect.set(mFrom.left, mFrom.top, mFrom.left + mFrozenTaskWidth,
mFrom.top + mFrozenTaskHeight);
+ // Boost the thread priority of the animation thread while the bounds animation is
+ // running
+ updateBooster();
+
// Ensure that we have prepared the target for animation before
// we trigger any size changes, so it can swap surfaces
// in to appropriate modes, or do as it wishes otherwise.
@@ -308,6 +320,9 @@ public class BoundsAnimationController {
removeListener(this);
removeUpdateListener(this);
mRunningAnimations.remove(mTarget);
+
+ // Reset the thread priority of the animation thread after the bounds animation is done
+ updateBooster();
}
@Override
@@ -350,6 +365,14 @@ public class BoundsAnimationController {
public void onAnimationRepeat(Animator animation) {
// Do nothing
}
+
+ @Override
+ public AnimationHandler getAnimationHandler() {
+ if (mAnimationHandler != null) {
+ return mAnimationHandler;
+ }
+ return super.getAnimationHandler();
+ }
}
public void animateBounds(final BoundsAnimationTarget target, Rect from, Rect to,
@@ -430,4 +453,9 @@ public class BoundsAnimationController {
b.resume();
}
}
+
+ private void updateBooster() {
+ WindowManagerService.sThreadPriorityBooster.setBoundsAnimationRunning(
+ !mRunningAnimations.isEmpty());
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ccc8f63e4355..54983c8998fc 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -314,6 +314,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// the display's direct children should be allowed.
private boolean mRemovingDisplay = false;
+ // {@code false} if this display is in the processing of being created.
+ private boolean mDisplayReady = false;
+
private final WindowLayersController mLayersController;
WallpaperController mWallpaperController;
int mInputMethodAnimLayerAdjustment;
@@ -720,7 +723,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
DisplayContent(Display display, WindowManagerService service,
WindowLayersController layersController, WallpaperController wallpaperController) {
-
if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
+ " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
@@ -748,6 +750,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// Add itself as a child to the root container.
mService.mRoot.addChild(this, null);
+
+ // TODO(b/62541591): evaluate whether this is the best spot to declare the
+ // {@link DisplayContent} ready for use.
+ mDisplayReady = true;
+ }
+
+ boolean isReady() {
+ // The display is ready when the system and the individual display are both ready.
+ return mService.mDisplayReady && mDisplayReady;
}
int getDisplayId() {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 03b5b827db74..aabf2bed1dd4 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -108,7 +108,8 @@ public class WindowAnimator {
}
void addDisplayLocked(final int displayId) {
- // Create the DisplayContentsAnimator object by retrieving it.
+ // Create the DisplayContentsAnimator object by retrieving it if the associated
+ // {@link DisplayContent} exists.
getDisplayContentsAnimatorLocked(displayId);
if (displayId == DEFAULT_DISPLAY) {
mInitialized = true;
@@ -356,8 +357,16 @@ public class WindowAnimator {
}
private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
+ if (displayId < 0) {
+ return null;
+ }
+
DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
- if (displayAnimator == null) {
+
+ // It is possible that this underlying {@link DisplayContent} has been removed. In this
+ // case, we do not want to create an animator associated with it as {link #animate} will
+ // fail.
+ if (displayAnimator == null && mService.mRoot.getDisplayContent(displayId) != null) {
displayAnimator = new DisplayContentsAnimator();
mDisplayContentsAnimators.put(displayId, displayAnimator);
}
@@ -365,8 +374,10 @@ public class WindowAnimator {
}
void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
- if (displayId >= 0) {
- getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
+ final DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId);
+
+ if (animator != null) {
+ animator.mScreenRotationAnimation = animation;
}
}
@@ -374,7 +385,9 @@ public class WindowAnimator {
if (displayId < 0) {
return null;
}
- return getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation;
+
+ DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId);
+ return animator != null? animator.mScreenRotationAnimation : null;
}
void requestRemovalOfReplacedWindows(WindowState win) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f8ede6cee9e3..41ddf0c093cd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -103,6 +103,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.Manifest;
import android.Manifest.permission;
+import android.animation.AnimationHandler;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -211,6 +212,7 @@ import android.view.inputmethod.InputMethodManagerInternal;
import com.android.internal.R;
import com.android.internal.app.IAssistScreenshotReceiver;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
@@ -1046,8 +1048,10 @@ public class WindowManagerService extends IWindowManager.Stub
mAppTransition = new AppTransition(context, this);
mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
+ final AnimationHandler animationHandler = new AnimationHandler();
+ animationHandler.setProvider(new SfVsyncFrameCallbackProvider());
mBoundsAnimationController = new BoundsAnimationController(context, mAppTransition,
- UiThread.getHandler());
+ AnimationThread.getHandler(), animationHandler);
mActivityManager = ActivityManager.getService();
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
@@ -5886,8 +5890,8 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- if (!mDisplayReady || !mPolicy.isScreenOn()) {
- // No need to freeze the screen before the system is ready or if
+ if (!displayContent.isReady() || !mPolicy.isScreenOn()) {
+ // No need to freeze the screen before the display is ready, system is ready, or if
// the screen is off.
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java
index 6a244a251537..1b2eb465399a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java
+++ b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java
@@ -23,6 +23,7 @@ import static android.os.Process.setThreadPriority;
import static com.android.server.LockGuard.INDEX_WINDOW;
import static com.android.server.am.ActivityManagerService.TOP_APP_PRIORITY_BOOST;
+import com.android.internal.annotations.GuardedBy;
import com.android.server.AnimationThread;
import com.android.server.ThreadPriorityBooster;
@@ -32,12 +33,18 @@ import com.android.server.ThreadPriorityBooster;
*/
class WindowManagerThreadPriorityBooster extends ThreadPriorityBooster {
- private final AnimationThread mAnimationThread;
+ private final Object mLock = new Object();
+
+ private final int mAnimationThreadId;
+
+ @GuardedBy("mLock")
private boolean mAppTransitionRunning;
+ @GuardedBy("mLock")
+ private boolean mBoundsAnimationRunning;
WindowManagerThreadPriorityBooster() {
super(THREAD_PRIORITY_DISPLAY, INDEX_WINDOW);
- mAnimationThread = AnimationThread.get();
+ mAnimationThreadId = AnimationThread.get().getThreadId();
}
@Override
@@ -45,7 +52,7 @@ class WindowManagerThreadPriorityBooster extends ThreadPriorityBooster {
// Do not boost the animation thread. As the animation thread is changing priorities,
// boosting it might mess up the priority because we reset it the the previous priority.
- if (myTid() == mAnimationThread.getThreadId()) {
+ if (myTid() == mAnimationThreadId) {
return;
}
super.boost();
@@ -55,24 +62,35 @@ class WindowManagerThreadPriorityBooster extends ThreadPriorityBooster {
public void reset() {
// See comment in boost().
- if (myTid() == mAnimationThread.getThreadId()) {
+ if (myTid() == mAnimationThreadId) {
return;
}
super.reset();
}
void setAppTransitionRunning(boolean running) {
- if (mAppTransitionRunning == running) {
- return;
+ synchronized (mLock) {
+ if (mAppTransitionRunning != running) {
+ mAppTransitionRunning = running;
+ updatePriorityLocked();
+ }
}
+ }
- final int priority = calculatePriority(running);
- setBoostToPriority(priority);
- setThreadPriority(mAnimationThread.getThreadId(), priority);
- mAppTransitionRunning = running;
+ void setBoundsAnimationRunning(boolean running) {
+ synchronized (mLock) {
+ if (mBoundsAnimationRunning != running) {
+ mBoundsAnimationRunning = running;
+ updatePriorityLocked();
+ }
+ }
}
- private int calculatePriority(boolean appTransitionRunning) {
- return appTransitionRunning ? TOP_APP_PRIORITY_BOOST : THREAD_PRIORITY_DISPLAY;
+ @GuardedBy("mLock")
+ private void updatePriorityLocked() {
+ int priority = (mAppTransitionRunning || mBoundsAnimationRunning)
+ ? TOP_APP_PRIORITY_BOOST : THREAD_PRIORITY_DISPLAY;
+ setBoostToPriority(priority);
+ setThreadPriority(mAnimationThreadId, priority);
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 272c11b985c5..eca285a1a27b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -454,7 +454,7 @@ public final class SystemServer {
// If '/cache/recovery/block.map' hasn't been created, stop the
// reboot which will fail for sure, and get a chance to capture a
// bugreport when that's still feasible. (Bug: 26444951)
- if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
+ if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
File packageFile = new File(UNCRYPT_PACKAGE_FILE);
if (packageFile.exists()) {
String filename = null;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java
index 89e18b4c2f41..40e114bfaef2 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java
@@ -491,12 +491,12 @@ public class MockStorageManager implements IStorageManager {
}
@Override
- public long getAllocatableBytes(String path, int flags) {
+ public long getAllocatableBytes(String path, int flags, String callingPackage) {
throw new UnsupportedOperationException();
}
@Override
- public void allocateBytes(String path, long bytes, int flags) {
+ public void allocateBytes(String path, long bytes, int flags, String callingPackage) {
throw new UnsupportedOperationException();
}
@@ -504,5 +504,4 @@ public class MockStorageManager implements IStorageManager {
public void secdiscard(String path) throws RemoteException {
throw new UnsupportedOperationException();
}
-
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index ee09f4bf7b94..9d32496c7817 100644
--- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -395,7 +395,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
mMockAppTransition = new MockAppTransition(context);
mMockAnimator = new MockValueAnimator();
mTarget = new TestBoundsAnimationTarget();
- mController = new BoundsAnimationController(context, mMockAppTransition, handler);
+ mController = new BoundsAnimationController(context, mMockAppTransition, handler, null);
mDriver = new BoundsAnimationDriver(mController, mTarget);
}
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 562443f53546..9f4fb85f64c4 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -197,7 +197,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
// logic should be kept in sync with getAllocatableBytes().
if (isQuotaSupported(volumeUuid, callingPackage)) {
final long cacheTotal = getCacheBytes(volumeUuid, callingPackage);
- final long cacheReserved = mStorage.getStorageCacheBytes(path);
+ final long cacheReserved = mStorage.getStorageCacheBytes(path, 0);
final long cacheClearable = Math.max(0, cacheTotal - cacheReserved);
return path.getUsableSpace() + cacheClearable;
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 640c9e12079b..de205380c3a7 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -325,7 +325,8 @@ public class Log {
return sEventManager;
}
- private static SessionManager getSessionManager() {
+ @VisibleForTesting
+ public static SessionManager getSessionManager() {
// Checking for null again outside of synchronization because we only need to synchronize
// during the lazy loading of the session logger. We don't need to synchronize elsewhere.
if (sSessionManager == null) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 331328d63841..b1eedf5cad4b 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -369,6 +369,15 @@ public class TelecomManager {
public static final String EXTRA_IS_HANDOVER = "android.telecom.extra.IS_HANDOVER";
/**
+ * Parcelable extra used with {@link #EXTRA_IS_HANDOVER} to indicate the source
+ * {@link PhoneAccountHandle} when initiating a handover which {@link ConnectionService}
+ * the handover is from.
+ * @hide
+ */
+ public static final String EXTRA_HANDOVER_FROM_PHONE_ACCOUNT =
+ "android.telecom.extra.HANDOVER_FROM_PHONE_ACCOUNT";
+
+ /**
* Extra key specified in the {@link ConnectionRequest#getExtras()} when Telecom calls
* {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}
* to inform the {@link ConnectionService} what the initial {@link CallAudioState} of the
diff --git a/tests/JobSchedulerTestApp/res/layout/activity_main.xml b/tests/JobSchedulerTestApp/res/layout/activity_main.xml
index 96e164103bce..41f977707097 100644
--- a/tests/JobSchedulerTestApp/res/layout/activity_main.xml
+++ b/tests/JobSchedulerTestApp/res/layout/activity_main.xml
@@ -73,10 +73,18 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
+ <RadioButton android:id="@+id/checkbox_none"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/none"/>
<RadioButton android:id="@+id/checkbox_any"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/any"/>
+ <RadioButton android:id="@+id/checkbox_metered"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/metered"/>
<RadioButton android:id="@+id/checkbox_unmetered"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/tests/JobSchedulerTestApp/res/values/strings.xml b/tests/JobSchedulerTestApp/res/values/strings.xml
index 90dd2b672fb2..866b61ecb308 100644
--- a/tests/JobSchedulerTestApp/res/values/strings.xml
+++ b/tests/JobSchedulerTestApp/res/values/strings.xml
@@ -30,7 +30,9 @@ limitations under the License.
<string name="persisted_caption">Persisted:</string>
<string name="constraints">Constraints</string>
<string name="connectivity">Connectivity:</string>
+ <string name="none">None</string>
<string name="any">Any</string>
+ <string name="metered">Metered</string>
<string name="unmetered">WiFi</string>
<string name="timing">Timing:</string>
<string name="delay">Delay:</string>
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
index 51cdbb585659..3dfdba719ce5 100644
--- a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
@@ -63,6 +63,7 @@ public class MainActivity extends Activity {
mDeadlineEditText = findViewById(R.id.deadline_time);
mWiFiConnectivityRadioButton = findViewById(R.id.checkbox_unmetered);
mAnyConnectivityRadioButton = findViewById(R.id.checkbox_any);
+ mCellConnectivityRadioButton = findViewById(R.id.checkbox_metered);
mRequiresChargingCheckBox = findViewById(R.id.checkbox_charging);
mRequiresIdleCheckbox = findViewById(R.id.checkbox_idle);
mIsPersistedCheckbox = findViewById(R.id.checkbox_persisted);
@@ -85,6 +86,7 @@ public class MainActivity extends Activity {
EditText mDeadlineEditText;
RadioButton mWiFiConnectivityRadioButton;
RadioButton mAnyConnectivityRadioButton;
+ RadioButton mCellConnectivityRadioButton;
CheckBox mRequiresChargingCheckBox;
CheckBox mRequiresIdleCheckbox;
CheckBox mIsPersistedCheckbox;
@@ -141,9 +143,12 @@ public class MainActivity extends Activity {
builder.setOverrideDeadline(Long.parseLong(deadline) * 1000);
}
boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked();
+ boolean requiresMetered = mCellConnectivityRadioButton.isChecked();
boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked();
if (requiresUnmetered) {
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
+ } else if (requiresMetered) {
+ builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_METERED);
} else if (requiresAnyConnectivity) {
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
}
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
index 9df11fe90553..b698a3a53ff1 100644
--- a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
@@ -81,7 +81,8 @@ public class TestJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
- Log.i(TAG, "on start job: " + params.getJobId());
+ Log.i(TAG, "on start job: " + params.getJobId()
+ + " deadline?=" + params.isOverrideDeadlineExpired());
currentId++;
jobParamsMap.put(currentId, params);
final int currId = this.currentId;
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index babbed02a11c..428c8bbe20e5 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -67,6 +67,7 @@ public class WifiAwareSession implements AutoCloseable {
* An application may re-attach after a destroy using
* {@link WifiAwareManager#attach(AttachCallback, Handler)} .
*/
+ @Override
public void close() {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 7f085f71e99c..f596eef1bf21 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -683,7 +683,7 @@ public class WifiP2pManager {
private DnsSdTxtRecordListener mDnsSdTxtListener;
private UpnpServiceResponseListener mUpnpServRspListener;
private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
- private Object mListenerMapLock = new Object();
+ private final Object mListenerMapLock = new Object();
private int mListenerKey = 0;
private AsyncChannel mAsyncChannel;