From bb01e5e538579ff170c8aeb4e75747ea786916e6 Mon Sep 17 00:00:00 2001
From: Felipe Leme
Date: Mon, 5 Mar 2018 14:09:15 -0800
Subject: [PATCH 001/488] Removed redundant method
ContentResolver.releasePersistableUriPermission()
Bug: 72055774
Test: manual verification
Test: atest CtsAppSecurityHostTestCases:ScopedDirectoryAccessTest#testResetGranted
Change-Id: Iab6dde04b0dc43f97e1a66f665cf5f6f3e078381
---
core/java/android/content/ContentResolver.java | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 10331d49dd3..ce7d3af8404 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2142,21 +2142,6 @@ public abstract class ContentResolver {
}
}
- /**
- * @hide
- */
- public void releasePersistableUriPermission(@NonNull String toPackage, @NonNull Uri uri,
- @Intent.AccessUriMode int modeFlags) {
- Preconditions.checkNotNull(toPackage, "toPackage");
- Preconditions.checkNotNull(uri, "uri");
- try {
- ActivityManager.getService().releasePersistableUriPermission(
- ContentProvider.getUriWithoutUserId(uri), modeFlags, toPackage,
- resolveUserId(uri));
- } catch (RemoteException e) {
- }
- }
-
/**
* Return list of all URI permission grants that have been persisted by the
* calling app. That is, the returned permissions have been granted
--
GitLab
From 2eee7760b594ca9aa51035e2253df1860ddfcebc Mon Sep 17 00:00:00 2001
From: xshu
Date: Thu, 1 Mar 2018 15:48:53 -0800
Subject: [PATCH 002/488] Deleting Visibility from WifiConfiguration
Removing @hide class that's not being used.
Bug: 74019502
Test: compile, run ./frameworks/base/wifi/tests/runtests.sh
This is CP from master fbce0f15544edc80b1ae49061f6fee365e3a2fea
Change-Id: I8b364bfa09f6fe6a585fbec01e5ff94b8b745bca
---
.../android/net/wifi/WifiConfiguration.java | 88 -------------------
1 file changed, 88 deletions(-)
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ddcf327b9dd..b0d86670a35 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -532,91 +532,6 @@ public class WifiConfiguration implements Parcelable {
/** @hide **/
public static int INVALID_RSSI = -127;
- /**
- * @hide
- * A summary of the RSSI and Band status for that configuration
- * This is used as a temporary value by the auto-join controller
- */
- public static final class Visibility {
- public int rssi5; // strongest 5GHz RSSI
- public int rssi24; // strongest 2.4GHz RSSI
- public int num5; // number of BSSIDs on 5GHz
- public int num24; // number of BSSIDs on 2.4GHz
- public long age5; // timestamp of the strongest 5GHz BSSID (last time it was seen)
- public long age24; // timestamp of the strongest 2.4GHz BSSID (last time it was seen)
- public String BSSID24;
- public String BSSID5;
- public int score; // Debug only, indicate last score used for autojoin/cell-handover
- public int currentNetworkBoost; // Debug only, indicate boost applied to RSSI if current
- public int bandPreferenceBoost; // Debug only, indicate boost applied to RSSI if current
- public int lastChoiceBoost; // Debug only, indicate last choice applied to this configuration
- public String lastChoiceConfig; // Debug only, indicate last choice applied to this configuration
-
- public Visibility() {
- rssi5 = INVALID_RSSI;
- rssi24 = INVALID_RSSI;
- }
-
- public Visibility(Visibility source) {
- rssi5 = source.rssi5;
- rssi24 = source.rssi24;
- age24 = source.age24;
- age5 = source.age5;
- num24 = source.num24;
- num5 = source.num5;
- BSSID5 = source.BSSID5;
- BSSID24 = source.BSSID24;
- }
-
- @Override
- public String toString() {
- StringBuilder sbuf = new StringBuilder();
- sbuf.append("[");
- if (rssi24 > INVALID_RSSI) {
- sbuf.append(Integer.toString(rssi24));
- sbuf.append(",");
- sbuf.append(Integer.toString(num24));
- if (BSSID24 != null) sbuf.append(",").append(BSSID24);
- }
- sbuf.append("; ");
- if (rssi5 > INVALID_RSSI) {
- sbuf.append(Integer.toString(rssi5));
- sbuf.append(",");
- sbuf.append(Integer.toString(num5));
- if (BSSID5 != null) sbuf.append(",").append(BSSID5);
- }
- if (score != 0) {
- sbuf.append("; ").append(score);
- sbuf.append(", ").append(currentNetworkBoost);
- sbuf.append(", ").append(bandPreferenceBoost);
- if (lastChoiceConfig != null) {
- sbuf.append(", ").append(lastChoiceBoost);
- sbuf.append(", ").append(lastChoiceConfig);
- }
- }
- sbuf.append("]");
- return sbuf.toString();
- }
- }
-
- /** @hide
- * Cache the visibility status of this configuration.
- * Visibility can change at any time depending on scan results availability.
- * Owner of the WifiConfiguration is responsible to set this field based on
- * recent scan results.
- ***/
- public Visibility visibility;
-
- /** @hide
- * calculate and set Visibility for that configuration.
- *
- * age in milliseconds: we will consider only ScanResults that are more recent,
- * i.e. younger.
- ***/
- public void setVisibility(Visibility status) {
- visibility = status;
- }
-
// States for the userApproved field
/**
* @hide
@@ -2177,9 +2092,6 @@ public class WifiConfiguration implements Parcelable {
meteredHint = source.meteredHint;
meteredOverride = source.meteredOverride;
useExternalScores = source.useExternalScores;
- if (source.visibility != null) {
- visibility = new Visibility(source.visibility);
- }
didSelfAdd = source.didSelfAdd;
lastConnectUid = source.lastConnectUid;
--
GitLab
From 4700befb26f078ba77eedf07ddb3d85f095b2b33 Mon Sep 17 00:00:00 2001
From: Andrew Grieve
Date: Tue, 13 Feb 2018 23:27:50 -0500
Subject: [PATCH 003/488] Add Application.getProcessName()
This information is already available to non-sandboxed processes via
ActivityManager.getRunningAppProcesses(). However, performing an IPC and
iterating processes is quite cumbersome. See other alternatives devs have tried:
https://stackoverflow.com/questions/19631894/is-there-a-way-to-get-current-process-name-in-android
My specific motivation for exposing this information more directly is to
be able to perform process-specific initialization logic in
Application.attachBaseContext():
https://cs.chromium.org/chromium/src/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java?rcl=ac2e180a1265f88dd4030bb35d69f5d0b2dc488d&l=54
Bug: 73344323
Test: Same code that's used in Chrome via reflection.
Change-Id: I83cec468458078e3fa183427a039869f74539c3d
---
api/current.txt | 1 +
core/java/android/app/Application.java | 12 +++++++++++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/api/current.txt b/api/current.txt
index 72666062c7f..186f66b91cc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4265,6 +4265,7 @@ package android.app {
public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
ctor public Application();
+ method public static java.lang.String getProcessName();
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onCreate();
method public void onLowMemory();
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 81cbbcafe8c..41eeb9acb5e 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -191,6 +191,16 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {
}
}
+ /**
+ * Returns the name of the current process. A package's default process name
+ * is the same as its package name. Non-default processes will look like
+ * "$PACKAGE_NAME:$NAME", where $NAME corresponds to an android:process
+ * attribute within AndroidManifest.xml.
+ */
+ public static String getProcessName() {
+ return ActivityThread.currentProcessName();
+ }
+
// ------------------ Internal API ------------------
/**
@@ -333,4 +343,4 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {
}
return null;
}
-}
\ No newline at end of file
+}
--
GitLab
From 004e73c38c799adfe5eaeceb96a5bc9aa3239b31 Mon Sep 17 00:00:00 2001
From: Emilian Peev
Date: Wed, 28 Feb 2018 14:53:30 +0000
Subject: [PATCH 004/488] Camera: SessionConfiguration should use Executors
Handlers from clients should not be used any more.
Executors are the preferred method for invoking any
registered callbacks. Replace handlers as much as
possible with executors.
Bug: 73953366
Test: Camera CTS
Change-Id: I96aee1bc46e83dfb76a4c40c7f8ebbe18610788b
---
api/current.txt | 4 +-
.../hardware/camera2/CameraDevice.java | 3 +-
.../dispatch/ArgumentReplacingDispatcher.java | 85 ---------
.../camera2/dispatch/BroadcastDispatcher.java | 64 -------
.../camera2/dispatch/Dispatchable.java | 35 ----
.../dispatch/DuckTypingDispatcher.java | 55 ------
.../camera2/dispatch/HandlerDispatcher.java | 85 ---------
.../camera2/dispatch/InvokeDispatcher.java | 55 ------
.../camera2/dispatch/MethodNameInvoker.java | 97 ----------
.../camera2/dispatch/NullDispatcher.java | 38 ----
.../hardware/camera2/dispatch/package.html | 3 -
.../camera2/impl/CallbackProxies.java | 179 +++++-------------
.../impl/CameraCaptureSessionImpl.java | 164 +++++++++-------
...onstrainedHighSpeedCaptureSessionImpl.java | 5 +-
.../camera2/impl/CameraDeviceImpl.java | 179 ++++++++++++------
.../camera2/params/SessionConfiguration.java | 25 ++-
.../hardware/camera2/utils/TaskDrainer.java | 26 ++-
.../camera2/utils/TaskSingleDrainer.java | 19 +-
18 files changed, 309 insertions(+), 812 deletions(-)
delete mode 100644 core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java
delete mode 100644 core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java
delete mode 100644 core/java/android/hardware/camera2/dispatch/Dispatchable.java
delete mode 100644 core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java
delete mode 100644 core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java
delete mode 100644 core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java
delete mode 100644 core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
delete mode 100644 core/java/android/hardware/camera2/dispatch/NullDispatcher.java
delete mode 100644 core/java/android/hardware/camera2/dispatch/package.html
diff --git a/api/current.txt b/api/current.txt
index 72666062c7f..e0b01cac3c1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16425,8 +16425,8 @@ package android.hardware.camera2.params {
}
public final class SessionConfiguration {
- ctor public SessionConfiguration(int, java.util.List, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler);
- method public android.os.Handler getHandler();
+ ctor public SessionConfiguration(int, java.util.List, java.util.concurrent.Executor, android.hardware.camera2.CameraCaptureSession.StateCallback);
+ method public java.util.concurrent.Executor getExecutor();
method public android.hardware.camera2.params.InputConfiguration getInputConfiguration();
method public java.util.List getOutputConfigurations();
method public android.hardware.camera2.CaptureRequest getSessionParameters();
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 72db33f90c2..f47d4640c09 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -819,7 +819,8 @@ public abstract class CameraDevice implements AutoCloseable {
* @param config A session configuration (see {@link SessionConfiguration}).
*
* @throws IllegalArgumentException In case the session configuration is invalid; or the output
- * configurations are empty.
+ * configurations are empty; or the session configuration
+ * executor is invalid.
* @throws CameraAccessException In case the camera device is no longer connected or has
* encountered a fatal error.
* @see #createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)
diff --git a/core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java b/core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java
deleted file mode 100644
index 866f370f5d5..00000000000
--- a/core/java/android/hardware/camera2/dispatch/ArgumentReplacingDispatcher.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.dispatch;
-
-import java.lang.reflect.Method;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * A dispatcher that replaces one argument with another; replaces any argument at an index
- * with another argument.
- *
- *
For example, we can override an {@code void onSomething(int x)} calls to have {@code x} always
- * equal to 1. Or, if using this with a duck typing dispatcher, we could even overwrite {@code x} to
- * be something
- * that's not an {@code int}.
- *
- * @param
- * source dispatch type, whose methods with {@link #dispatch} will be called
- * @param
- * argument replacement type, args in {@link #dispatch} matching {@code argumentIndex}
- * will be overriden to objects of this type
- */
-public class ArgumentReplacingDispatcher implements Dispatchable {
-
- private final Dispatchable mTarget;
- private final int mArgumentIndex;
- private final TArg mReplaceWith;
-
- /**
- * Create a new argument replacing dispatcher; dispatches are forwarded to {@code target}
- * after the argument is replaced.
- *
- *
For example, if a method {@code onAction(T1 a, Integer b, T2 c)} is invoked, and we wanted
- * to replace all occurrences of {@code b} with {@code 0xDEADBEEF}, we would set
- * {@code argumentIndex = 1} and {@code replaceWith = 0xDEADBEEF}.
- *
- *
If a method dispatched has less arguments than {@code argumentIndex}, it is
- * passed through with the arguments unchanged.
- *
- * @param target destination dispatch type, methods will be redirected to this dispatcher
- * @param argumentIndex the numeric index of the argument {@code >= 0}
- * @param replaceWith arguments matching {@code argumentIndex} will be replaced with this object
- */
- public ArgumentReplacingDispatcher(Dispatchable target, int argumentIndex,
- TArg replaceWith) {
- mTarget = checkNotNull(target, "target must not be null");
- mArgumentIndex = checkArgumentNonnegative(argumentIndex,
- "argumentIndex must not be negative");
- mReplaceWith = checkNotNull(replaceWith, "replaceWith must not be null");
- }
-
- @Override
- public Object dispatch(Method method, Object[] args) throws Throwable {
-
- if (args.length > mArgumentIndex) {
- args = arrayCopy(args); // don't change in-place since it can affect upstream dispatches
- args[mArgumentIndex] = mReplaceWith;
- }
-
- return mTarget.dispatch(method, args);
- }
-
- private static Object[] arrayCopy(Object[] array) {
- int length = array.length;
- Object[] newArray = new Object[length];
- for (int i = 0; i < length; ++i) {
- newArray[i] = array[i];
- }
- return newArray;
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java b/core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java
deleted file mode 100644
index fe575b27761..00000000000
--- a/core/java/android/hardware/camera2/dispatch/BroadcastDispatcher.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.dispatch;
-
-
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.List;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Broadcast a single dispatch into multiple other dispatchables.
- *
- *
Every time {@link #dispatch} is invoked, all the broadcast targets will
- * see the same dispatch as well. The first target's return value is returned.
- *
- *
This enables a single listener to be converted into a multi-listener.
- */
-public class BroadcastDispatcher implements Dispatchable {
-
- private final List> mDispatchTargets;
-
- /**
- * Create a broadcast dispatcher from the supplied dispatch targets.
- *
- * @param dispatchTargets one or more targets to dispatch to
- */
- @SafeVarargs
- public BroadcastDispatcher(Dispatchable... dispatchTargets) {
- mDispatchTargets = Arrays.asList(
- checkNotNull(dispatchTargets, "dispatchTargets must not be null"));
- }
-
- @Override
- public Object dispatch(Method method, Object[] args) throws Throwable {
- Object result = null;
- boolean gotResult = false;
-
- for (Dispatchable dispatchTarget : mDispatchTargets) {
- Object localResult = dispatchTarget.dispatch(method, args);
-
- if (!gotResult) {
- gotResult = true;
- result = localResult;
- }
- }
-
- return result;
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/Dispatchable.java b/core/java/android/hardware/camera2/dispatch/Dispatchable.java
deleted file mode 100644
index 753103f45ea..00000000000
--- a/core/java/android/hardware/camera2/dispatch/Dispatchable.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.dispatch;
-
-import java.lang.reflect.Method;
-
-/**
- * Dynamically dispatch a method and its argument to some object.
- *
- *
This can be used to intercept method calls and do work around them, redirect work,
- * or block calls entirely.
- */
-public interface Dispatchable {
- /**
- * Dispatch the method and arguments to this object.
- * @param method a method defined in class {@code T}
- * @param args arguments corresponding to said {@code method}
- * @return the object returned when invoking {@code method}
- * @throws Throwable any exception that might have been raised while invoking the method
- */
- public Object dispatch(Method method, Object[] args) throws Throwable;
-}
diff --git a/core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java b/core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java
deleted file mode 100644
index 75f97e4656a..00000000000
--- a/core/java/android/hardware/camera2/dispatch/DuckTypingDispatcher.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.dispatch;
-
-
-import java.lang.reflect.Method;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Duck typing dispatcher; converts dispatch methods calls from one class to another by
- * looking up equivalently methods at runtime by name.
- *
- *
For example, if two types have identical method names and arguments, but
- * are not subclasses/subinterfaces of each other, this dispatcher will allow calls to be
- * made from one type to the other.
- *
- * @param source dispatch type, whose methods with {@link #dispatch} will be called
- * @param destination dispatch type, methods will be converted to the class of {@code T}
- */
-public class DuckTypingDispatcher implements Dispatchable {
-
- private final MethodNameInvoker mDuck;
-
- /**
- * Create a new duck typing dispatcher.
- *
- * @param target destination dispatch type, methods will be redirected to this dispatcher
- * @param targetClass destination dispatch class, methods will be converted to this class's
- */
- public DuckTypingDispatcher(Dispatchable target, Class targetClass) {
- checkNotNull(targetClass, "targetClass must not be null");
- checkNotNull(target, "target must not be null");
-
- mDuck = new MethodNameInvoker(target, targetClass);
- }
-
- @Override
- public Object dispatch(Method method, Object[] args) {
- return mDuck.invoke(method.getName(), args);
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java b/core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java
deleted file mode 100644
index f8e9d49a95c..00000000000
--- a/core/java/android/hardware/camera2/dispatch/HandlerDispatcher.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.dispatch;
-
-import android.hardware.camera2.utils.UncheckedThrow;
-import android.os.Handler;
-import android.util.Log;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Forward all interface calls into a handler by posting it as a {@code Runnable}.
- *
- *
All calls will return immediately; functions with return values will return a default
- * value of {@code null}, {@code 0}, or {@code false} where that value is legal.
- *
- *
Any exceptions thrown on the handler while trying to invoke a method
- * will be re-thrown. Throwing checked exceptions on a handler which doesn't expect any
- * checked exceptions to be thrown will result in "undefined" behavior
- * (although in practice it is usually thrown as normal).
- */
-public class HandlerDispatcher implements Dispatchable {
-
- private static final String TAG = "HandlerDispatcher";
-
- private final Dispatchable mDispatchTarget;
- private final Handler mHandler;
-
- /**
- * Create a dispatcher that forwards it's dispatch calls by posting
- * them onto the {@code handler} as a {@code Runnable}.
- *
- * @param dispatchTarget the destination whose method calls will be redirected into the handler
- * @param handler all calls into {@code dispatchTarget} will be posted onto this handler
- * @param the type of the element you want to wrap.
- * @return a dispatcher that will forward it's dispatch calls to a handler
- */
- public HandlerDispatcher(Dispatchable dispatchTarget, Handler handler) {
- mDispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
- mHandler = checkNotNull(handler, "handler must not be null");
- }
-
- @Override
- public Object dispatch(final Method method, final Object[] args) throws Throwable {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- mDispatchTarget.dispatch(method, args);
- } catch (InvocationTargetException e) {
- Throwable t = e.getTargetException();
- // Potential UB. Hopefully 't' is a runtime exception.
- UncheckedThrow.throwAnyException(t);
- } catch (IllegalAccessException e) {
- // Impossible
- Log.wtf(TAG, "IllegalAccessException while invoking " + method, e);
- } catch (IllegalArgumentException e) {
- // Impossible
- Log.wtf(TAG, "IllegalArgumentException while invoking " + method, e);
- } catch (Throwable e) {
- UncheckedThrow.throwAnyException(e);
- }
- }
- });
-
- // TODO handle primitive return values that would avoid NPE if unboxed
- return null;
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java b/core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java
deleted file mode 100644
index ac5f52676df..00000000000
--- a/core/java/android/hardware/camera2/dispatch/InvokeDispatcher.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.dispatch;
-
-import android.hardware.camera2.utils.UncheckedThrow;
-import android.util.Log;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import static com.android.internal.util.Preconditions.*;
-
-
-public class InvokeDispatcher implements Dispatchable {
-
- private static final String TAG = "InvocationSink";
- private final T mTarget;
-
- public InvokeDispatcher(T target) {
- mTarget = checkNotNull(target, "target must not be null");
- }
-
- @Override
- public Object dispatch(Method method, Object[] args) {
- try {
- return method.invoke(mTarget, args);
- } catch (InvocationTargetException e) {
- Throwable t = e.getTargetException();
- // Potential UB. Hopefully 't' is a runtime exception.
- UncheckedThrow.throwAnyException(t);
- } catch (IllegalAccessException e) {
- // Impossible
- Log.wtf(TAG, "IllegalAccessException while invoking " + method, e);
- } catch (IllegalArgumentException e) {
- // Impossible
- Log.wtf(TAG, "IllegalArgumentException while invoking " + method, e);
- }
-
- // unreachable
- return null;
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
deleted file mode 100644
index 8296b7a915a..00000000000
--- a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.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;
-
-/**
- * Invoke a method on a dispatchable by its name (without knowing the {@code Method} ahead of time).
- *
- * @param destination dispatch type, methods will be looked up in the class of {@code T}
- */
-public class MethodNameInvoker {
-
- private final Dispatchable mTarget;
- private final Class mTargetClass;
- private final Method[] mTargetClassMethods;
- private final ConcurrentHashMap mMethods =
- new ConcurrentHashMap<>();
-
- /**
- * Create a new method name invoker.
- *
- * @param target destination dispatch type, invokes will be redirected to this dispatcher
- * @param targetClass destination dispatch class, the invoked methods will be from this class
- */
- public MethodNameInvoker(Dispatchable target, Class targetClass) {
- mTargetClass = targetClass;
- mTargetClassMethods = targetClass.getMethods();
- mTarget = target;
- }
-
- /**
- * Invoke a method by its name.
- *
- *
If more than one method exists in {@code targetClass}, the first method with the right
- * number of arguments will be used, and later calls will all use that method.
- *
- * @param methodName
- * The name of the method, which will be matched 1:1 to the destination method
- * @param params
- * Variadic parameter list.
- * @return
- * The same kind of value that would normally be returned by calling {@code methodName}
- * statically.
- *
- * @throws IllegalArgumentException if {@code methodName} does not exist on the target class
- * @throws Throwable will rethrow anything that the target method would normally throw
- */
- @SuppressWarnings("unchecked")
- public K invoke(String methodName, Object... params) {
- checkNotNull(methodName, "methodName must not be null");
-
- Method targetMethod = mMethods.get(methodName);
- if (targetMethod == null) {
- for (Method method : mTargetClassMethods) {
- // TODO future: match types of params if possible
- if (method.getName().equals(methodName) &&
- (params.length == method.getParameterTypes().length) ) {
- targetMethod = method;
- mMethods.put(methodName, targetMethod);
- break;
- }
- }
-
- if (targetMethod == null) {
- throw new IllegalArgumentException(
- "Method " + methodName + " does not exist on class " + mTargetClass);
- }
- }
-
- try {
- return (K) mTarget.dispatch(targetMethod, params);
- } catch (Throwable e) {
- UncheckedThrow.throwAnyException(e);
- // unreachable
- return null;
- }
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/NullDispatcher.java b/core/java/android/hardware/camera2/dispatch/NullDispatcher.java
deleted file mode 100644
index fada075cba6..00000000000
--- a/core/java/android/hardware/camera2/dispatch/NullDispatcher.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.dispatch;
-
-
-import java.lang.reflect.Method;
-
-/**
- * Do nothing when dispatching; follows the null object pattern.
- */
-public class NullDispatcher implements Dispatchable {
- /**
- * Create a dispatcher that does nothing when dispatched to.
- */
- public NullDispatcher() {
- }
-
- /**
- * Do nothing; all parameters are ignored.
- */
- @Override
- public Object dispatch(Method method, Object[] args) {
- return null;
- }
-}
diff --git a/core/java/android/hardware/camera2/dispatch/package.html b/core/java/android/hardware/camera2/dispatch/package.html
deleted file mode 100644
index 783d0a1b54d..00000000000
--- a/core/java/android/hardware/camera2/dispatch/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-{@hide}
-
diff --git a/core/java/android/hardware/camera2/impl/CallbackProxies.java b/core/java/android/hardware/camera2/impl/CallbackProxies.java
index c9eecf10e3d..9e4cb80b89f 100644
--- a/core/java/android/hardware/camera2/impl/CallbackProxies.java
+++ b/core/java/android/hardware/camera2/impl/CallbackProxies.java
@@ -15,16 +15,17 @@
*/
package android.hardware.camera2.impl;
+import android.os.Binder;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
-import android.hardware.camera2.dispatch.Dispatchable;
-import android.hardware.camera2.dispatch.MethodNameInvoker;
import android.view.Surface;
+import java.util.concurrent.Executor;
+
import static com.android.internal.util.Preconditions.*;
/**
@@ -34,164 +35,86 @@ import static com.android.internal.util.Preconditions.*;
* to use our own proxy mechanism.
*/
public class CallbackProxies {
-
- // TODO: replace with codegen
-
- public static class DeviceStateCallbackProxy extends CameraDeviceImpl.StateCallbackKK {
- private final MethodNameInvoker mProxy;
-
- public DeviceStateCallbackProxy(
- Dispatchable dispatchTarget) {
- dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
- mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.StateCallbackKK.class);
- }
-
- @Override
- public void onOpened(CameraDevice camera) {
- mProxy.invoke("onOpened", camera);
- }
-
- @Override
- public void onDisconnected(CameraDevice camera) {
- mProxy.invoke("onDisconnected", camera);
- }
-
- @Override
- public void onError(CameraDevice camera, int error) {
- mProxy.invoke("onError", camera, error);
- }
-
- @Override
- public void onUnconfigured(CameraDevice camera) {
- mProxy.invoke("onUnconfigured", camera);
- }
-
- @Override
- public void onActive(CameraDevice camera) {
- mProxy.invoke("onActive", camera);
- }
-
- @Override
- public void onBusy(CameraDevice camera) {
- mProxy.invoke("onBusy", camera);
- }
-
- @Override
- public void onClosed(CameraDevice camera) {
- mProxy.invoke("onClosed", camera);
- }
-
- @Override
- public void onIdle(CameraDevice camera) {
- mProxy.invoke("onIdle", camera);
- }
- }
-
- @SuppressWarnings("deprecation")
- public static class DeviceCaptureCallbackProxy implements CameraDeviceImpl.CaptureCallback {
- private final MethodNameInvoker mProxy;
-
- public DeviceCaptureCallbackProxy(
- Dispatchable dispatchTarget) {
- dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
- mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.CaptureCallback.class);
- }
-
- @Override
- public void onCaptureStarted(CameraDevice camera,
- CaptureRequest request, long timestamp, long frameNumber) {
- mProxy.invoke("onCaptureStarted", camera, request, timestamp, frameNumber);
- }
-
- @Override
- public void onCapturePartial(CameraDevice camera,
- CaptureRequest request, CaptureResult result) {
- mProxy.invoke("onCapturePartial", camera, request, result);
- }
-
- @Override
- public void onCaptureProgressed(CameraDevice camera,
- CaptureRequest request, CaptureResult partialResult) {
- mProxy.invoke("onCaptureProgressed", camera, request, partialResult);
- }
-
- @Override
- public void onCaptureCompleted(CameraDevice camera,
- CaptureRequest request, TotalCaptureResult result) {
- mProxy.invoke("onCaptureCompleted", camera, request, result);
- }
-
- @Override
- public void onCaptureFailed(CameraDevice camera,
- CaptureRequest request, CaptureFailure failure) {
- mProxy.invoke("onCaptureFailed", camera, request, failure);
- }
-
- @Override
- public void onCaptureSequenceCompleted(CameraDevice camera,
- int sequenceId, long frameNumber) {
- mProxy.invoke("onCaptureSequenceCompleted", camera, sequenceId, frameNumber);
- }
-
- @Override
- public void onCaptureSequenceAborted(CameraDevice camera,
- int sequenceId) {
- mProxy.invoke("onCaptureSequenceAborted", camera, sequenceId);
- }
-
- @Override
- public void onCaptureBufferLost(CameraDevice camera,
- CaptureRequest request, Surface target, long frameNumber) {
- mProxy.invoke("onCaptureBufferLost", camera, request, target, frameNumber);
- }
-
- }
-
public static class SessionStateCallbackProxy
extends CameraCaptureSession.StateCallback {
- private final MethodNameInvoker mProxy;
+ private final Executor mExecutor;
+ private final CameraCaptureSession.StateCallback mCallback;
- public SessionStateCallbackProxy(
- Dispatchable dispatchTarget) {
- dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
- mProxy = new MethodNameInvoker<>(dispatchTarget,
- CameraCaptureSession.StateCallback.class);
+ public SessionStateCallbackProxy(Executor executor,
+ CameraCaptureSession.StateCallback callback) {
+ mExecutor = checkNotNull(executor, "executor must not be null");
+ mCallback = checkNotNull(callback, "callback must not be null");
}
@Override
public void onConfigured(CameraCaptureSession session) {
- mProxy.invoke("onConfigured", session);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onConfigured(session));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
- mProxy.invoke("onConfigureFailed", session);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onConfigureFailed(session));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
public void onReady(CameraCaptureSession session) {
- mProxy.invoke("onReady", session);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onReady(session));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
public void onActive(CameraCaptureSession session) {
- mProxy.invoke("onActive", session);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onActive(session));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
public void onCaptureQueueEmpty(CameraCaptureSession session) {
- mProxy.invoke("onCaptureQueueEmpty", session);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onCaptureQueueEmpty(session));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
public void onClosed(CameraCaptureSession session) {
- mProxy.invoke("onClosed", session);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onClosed(session));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
- mProxy.invoke("onSurfacePrepared", session, surface);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onSurfacePrepared(session, surface));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 8b8bbc34f7d..f3f6c84a7e0 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -20,20 +20,18 @@ import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.ICameraDeviceUser;
-import android.hardware.camera2.dispatch.ArgumentReplacingDispatcher;
-import android.hardware.camera2.dispatch.BroadcastDispatcher;
-import android.hardware.camera2.dispatch.DuckTypingDispatcher;
-import android.hardware.camera2.dispatch.HandlerDispatcher;
-import android.hardware.camera2.dispatch.InvokeDispatcher;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.utils.TaskDrainer;
import android.hardware.camera2.utils.TaskSingleDrainer;
+import android.os.Binder;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.util.Log;
import android.view.Surface;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.Executor;
import static android.hardware.camera2.impl.CameraDeviceImpl.checkHandler;
import static com.android.internal.util.Preconditions.*;
@@ -51,11 +49,11 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
private final Surface mInput;
/**
* User-specified state callback, used for outgoing events; calls to this object will be
- * automatically {@link Handler#post(Runnable) posted} to {@code mStateHandler}.
+ * automatically invoked via {@code mStateExecutor}.
*/
private final CameraCaptureSession.StateCallback mStateCallback;
- /** User-specified state handler used for outgoing state callback events */
- private final Handler mStateHandler;
+ /** User-specified state executor used for outgoing state callback events */
+ private final Executor mStateExecutor;
/** Internal camera device; used to translate calls into existing deprecated API */
private final android.hardware.camera2.impl.CameraDeviceImpl mDeviceImpl;
@@ -87,7 +85,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
* (e.g. no pending captures, no repeating requests, no flush).
*/
CameraCaptureSessionImpl(int id, Surface input,
- CameraCaptureSession.StateCallback callback, Handler stateHandler,
+ CameraCaptureSession.StateCallback callback, Executor stateExecutor,
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
Handler deviceStateHandler, boolean configureSuccess) {
if (callback == null) {
@@ -98,8 +96,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
mIdString = String.format("Session %d: ", mId);
mInput = input;
- mStateHandler = checkHandler(stateHandler);
- mStateCallback = createUserStateCallbackProxy(mStateHandler, callback);
+ mStateExecutor = checkNotNull(stateExecutor, "stateExecutor must not be null");
+ mStateCallback = createUserStateCallbackProxy(mStateExecutor, callback);
mDeviceHandler = checkNotNull(deviceStateHandler, "deviceStateHandler must not be null");
mDeviceImpl = checkNotNull(deviceImpl, "deviceImpl must not be null");
@@ -110,12 +108,12 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
* This ensures total ordering between CameraDevice.StateCallback and
* CameraDeviceImpl.CaptureCallback events.
*/
- mSequenceDrainer = new TaskDrainer<>(mDeviceHandler, new SequenceDrainListener(),
- /*name*/"seq");
- mIdleDrainer = new TaskSingleDrainer(mDeviceHandler, new IdleDrainListener(),
- /*name*/"idle");
- mAbortDrainer = new TaskSingleDrainer(mDeviceHandler, new AbortDrainListener(),
- /*name*/"abort");
+ mSequenceDrainer = new TaskDrainer<>(new HandlerExecutor(mDeviceHandler),
+ new SequenceDrainListener(), /*name*/"seq");
+ mIdleDrainer = new TaskSingleDrainer(new HandlerExecutor(mDeviceHandler),
+ new IdleDrainListener(), /*name*/"idle");
+ mAbortDrainer = new TaskSingleDrainer(new HandlerExecutor(mDeviceHandler),
+ new AbortDrainListener(), /*name*/"abort");
// CameraDevice should call configureOutputs and have it finish before constructing us
@@ -446,114 +444,140 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
}
/**
- * Post calls into a CameraCaptureSession.StateCallback to the user-specified {@code handler}.
+ * Post calls into a CameraCaptureSession.StateCallback to the user-specified {@code executor}.
*/
- private StateCallback createUserStateCallbackProxy(Handler handler, StateCallback callback) {
- InvokeDispatcher userCallbackSink = new InvokeDispatcher<>(callback);
- HandlerDispatcher handlerPassthrough =
- new HandlerDispatcher<>(userCallbackSink, handler);
-
- return new CallbackProxies.SessionStateCallbackProxy(handlerPassthrough);
+ private StateCallback createUserStateCallbackProxy(Executor executor, StateCallback callback) {
+ return new CallbackProxies.SessionStateCallbackProxy(executor, callback);
}
/**
* Forward callbacks from
* CameraDeviceImpl.CaptureCallback to the CameraCaptureSession.CaptureCallback.
*
- *
In particular, all calls are automatically split to go both to our own
- * internal callback, and to the user-specified callback (by transparently posting
- * to the user-specified handler).
- *
*
When a capture sequence finishes, update the pending checked sequences set.
*/
@SuppressWarnings("deprecation")
private CameraDeviceImpl.CaptureCallback createCaptureCallbackProxy(
Handler handler, CaptureCallback callback) {
- CameraDeviceImpl.CaptureCallback localCallback = new CameraDeviceImpl.CaptureCallback() {
+ final Executor executor = (callback != null) ? CameraDeviceImpl.checkAndWrapHandler(
+ handler) : null;
+ return new CameraDeviceImpl.CaptureCallback() {
@Override
public void onCaptureStarted(CameraDevice camera,
CaptureRequest request, long timestamp, long frameNumber) {
- // Do nothing
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureStarted(
+ CameraCaptureSessionImpl.this, request, timestamp,
+ frameNumber));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
@Override
public void onCapturePartial(CameraDevice camera,
CaptureRequest request, android.hardware.camera2.CaptureResult result) {
- // Do nothing
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCapturePartial(
+ CameraCaptureSessionImpl.this, request, result));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
@Override
public void onCaptureProgressed(CameraDevice camera,
CaptureRequest request, android.hardware.camera2.CaptureResult partialResult) {
- // Do nothing
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureProgressed(
+ CameraCaptureSessionImpl.this, request, partialResult));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
@Override
public void onCaptureCompleted(CameraDevice camera,
CaptureRequest request, android.hardware.camera2.TotalCaptureResult result) {
- // Do nothing
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureCompleted(
+ CameraCaptureSessionImpl.this, request, result));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
@Override
public void onCaptureFailed(CameraDevice camera,
CaptureRequest request, android.hardware.camera2.CaptureFailure failure) {
- // Do nothing
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureFailed(
+ CameraCaptureSessionImpl.this, request, failure));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
@Override
public void onCaptureSequenceCompleted(CameraDevice camera,
int sequenceId, long frameNumber) {
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureSequenceCompleted(
+ CameraCaptureSessionImpl.this, sequenceId, frameNumber));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
finishPendingSequence(sequenceId);
}
@Override
public void onCaptureSequenceAborted(CameraDevice camera,
int sequenceId) {
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureSequenceAborted(
+ CameraCaptureSessionImpl.this, sequenceId));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
finishPendingSequence(sequenceId);
}
@Override
public void onCaptureBufferLost(CameraDevice camera,
CaptureRequest request, Surface target, long frameNumber) {
- // Do nothing
+ if ((callback != null) && (executor != null)) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCaptureBufferLost(
+ CameraCaptureSessionImpl.this, request, target, frameNumber));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
-
};
-
- /*
- * Split the calls from the device callback into local callback and the following chain:
- * - replace the first CameraDevice arg with a CameraCaptureSession
- * - duck type from device callback to session callback
- * - then forward the call to a handler
- * - then finally invoke the destination method on the session callback object
- */
- if (callback == null) {
- // OK: API allows the user to not specify a callback, and the handler may
- // also be null in that case. Collapse whole dispatch chain to only call the local
- // callback
- return localCallback;
- }
-
- InvokeDispatcher localSink =
- new InvokeDispatcher<>(localCallback);
-
- InvokeDispatcher userCallbackSink =
- new InvokeDispatcher<>(callback);
- HandlerDispatcher handlerPassthrough =
- new HandlerDispatcher<>(userCallbackSink, handler);
- DuckTypingDispatcher duckToSession
- = new DuckTypingDispatcher<>(handlerPassthrough, CaptureCallback.class);
- ArgumentReplacingDispatcher
- replaceDeviceWithSession = new ArgumentReplacingDispatcher<>(duckToSession,
- /*argumentIndex*/0, this);
-
- BroadcastDispatcher broadcaster =
- new BroadcastDispatcher(
- replaceDeviceWithSession,
- localSink);
-
- return new CallbackProxies.DeviceCaptureCallbackProxy(broadcaster);
}
/**
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index 06c2c25ab6b..4ee08bae84c 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -33,6 +33,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.Executor;
import static com.android.internal.util.Preconditions.*;
@@ -59,14 +60,14 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl
* (e.g. no pending captures, no repeating requests, no flush).
*/
CameraConstrainedHighSpeedCaptureSessionImpl(int id,
- CameraCaptureSession.StateCallback callback, Handler stateHandler,
+ CameraCaptureSession.StateCallback callback, Executor stateExecutor,
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
Handler deviceStateHandler, boolean configureSuccess,
CameraCharacteristics characteristics) {
mCharacteristics = characteristics;
CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback);
mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback,
- stateHandler, deviceImpl, deviceStateHandler, configureSuccess);
+ stateExecutor, deviceImpl, deviceStateHandler, configureSuccess);
}
@Override
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 511fa43a544..b328bb1726e 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -35,8 +35,10 @@ import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.SubmitInfo;
import android.hardware.camera2.utils.SurfaceUtils;
+import android.os.Binder;
import android.os.Build;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
@@ -58,6 +60,7 @@ import java.util.List;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.Executor;
/**
* HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
@@ -501,8 +504,9 @@ public class CameraDeviceImpl extends CameraDevice
for (Surface surface : outputs) {
outConfigurations.add(new OutputConfiguration(surface));
}
- createCaptureSessionInternal(null, outConfigurations, callback, handler,
- /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
+ createCaptureSessionInternal(null, outConfigurations, callback,
+ checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
+ /*sessionParams*/ null);
}
@Override
@@ -517,7 +521,7 @@ public class CameraDeviceImpl extends CameraDevice
// OutputConfiguration objects are immutable, but need to have our own array
List currentOutputs = new ArrayList<>(outputConfigurations);
- createCaptureSessionInternal(null, currentOutputs, callback, handler,
+ createCaptureSessionInternal(null, currentOutputs, callback, checkAndWrapHandler(handler),
/*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/null);
}
@@ -537,8 +541,9 @@ public class CameraDeviceImpl extends CameraDevice
for (Surface surface : outputs) {
outConfigurations.add(new OutputConfiguration(surface));
}
- createCaptureSessionInternal(inputConfig, outConfigurations, callback, handler,
- /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
+ createCaptureSessionInternal(inputConfig, outConfigurations, callback,
+ checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
+ /*sessionParams*/ null);
}
@Override
@@ -566,8 +571,8 @@ public class CameraDeviceImpl extends CameraDevice
currentOutputs.add(new OutputConfiguration(output));
}
createCaptureSessionInternal(inputConfig, currentOutputs,
- callback, handler, /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
- /*sessionParams*/ null);
+ callback, checkAndWrapHandler(handler),
+ /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null);
}
@Override
@@ -582,7 +587,8 @@ public class CameraDeviceImpl extends CameraDevice
for (Surface surface : outputs) {
outConfigurations.add(new OutputConfiguration(surface));
}
- createCaptureSessionInternal(null, outConfigurations, callback, handler,
+ createCaptureSessionInternal(null, outConfigurations, callback,
+ checkAndWrapHandler(handler),
/*operatingMode*/ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE,
/*sessionParams*/ null);
}
@@ -597,8 +603,8 @@ public class CameraDeviceImpl extends CameraDevice
for (OutputConfiguration output : outputs) {
currentOutputs.add(new OutputConfiguration(output));
}
- createCaptureSessionInternal(inputConfig, currentOutputs, callback, handler, operatingMode,
- /*sessionParams*/ null);
+ createCaptureSessionInternal(inputConfig, currentOutputs, callback,
+ checkAndWrapHandler(handler), operatingMode, /*sessionParams*/ null);
}
@Override
@@ -612,14 +618,17 @@ public class CameraDeviceImpl extends CameraDevice
if (outputConfigs == null) {
throw new IllegalArgumentException("Invalid output configurations");
}
+ if (config.getExecutor() == null) {
+ throw new IllegalArgumentException("Invalid executor");
+ }
createCaptureSessionInternal(config.getInputConfiguration(), outputConfigs,
- config.getStateCallback(), config.getHandler(), config.getSessionType(),
+ config.getStateCallback(), config.getExecutor(), config.getSessionType(),
config.getSessionParameters());
}
private void createCaptureSessionInternal(InputConfiguration inputConfig,
List outputConfigurations,
- CameraCaptureSession.StateCallback callback, Handler handler,
+ CameraCaptureSession.StateCallback callback, Executor executor,
int operatingMode, CaptureRequest sessionParams) throws CameraAccessException {
synchronized(mInterfaceLock) {
if (DEBUG) {
@@ -673,12 +682,11 @@ public class CameraDeviceImpl extends CameraDevice
SurfaceUtils.checkConstrainedHighSpeedSurfaces(surfaces, /*fpsRange*/null, config);
newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
- callback, handler, this, mDeviceHandler, configureSuccess,
+ callback, executor, this, mDeviceHandler, configureSuccess,
mCharacteristics);
} else {
newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
- callback, handler, this, mDeviceHandler,
- configureSuccess);
+ callback, executor, this, mDeviceHandler, configureSuccess);
}
// TODO: wait until current session closes, then create the new session
@@ -963,7 +971,12 @@ public class CameraDeviceImpl extends CameraDevice
}
}
};
- holder.getHandler().post(resultDispatch);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ holder.getExecutor().execute(resultDispatch);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
} else {
Log.w(TAG, String.format(
"did not register callback to request %d",
@@ -984,9 +997,9 @@ public class CameraDeviceImpl extends CameraDevice
private int submitCaptureRequest(List requestList, CaptureCallback callback,
Handler handler, boolean repeating) throws CameraAccessException {
- // Need a valid handler, or current thread needs to have a looper, if
+ // Need a valid executor, or current thread needs to have a looper, if
// callback is valid
- handler = checkHandler(handler, callback);
+ Executor executor = getExecutor(handler, callback);
// Make sure that there all requests have at least 1 surface; all surfaces are non-null;
// the surface isn't a physical stream surface for reprocessing request
@@ -1040,7 +1053,7 @@ public class CameraDeviceImpl extends CameraDevice
if (callback != null) {
mCaptureCallbackMap.put(requestInfo.getRequestId(),
new CaptureCallbackHolder(
- callback, requestList, handler, repeating, mNextSessionId - 1));
+ callback, requestList, executor, repeating, mNextSessionId - 1));
} else {
if (DEBUG) {
Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
@@ -1354,7 +1367,7 @@ public class CameraDeviceImpl extends CameraDevice
private final boolean mRepeating;
private final CaptureCallback mCallback;
private final List mRequestList;
- private final Handler mHandler;
+ private final Executor mExecutor;
private final int mSessionId;
/**
*
Determine if the callback holder is for a constrained high speed request list that
@@ -1366,13 +1379,13 @@ public class CameraDeviceImpl extends CameraDevice
private final boolean mHasBatchedOutputs;
CaptureCallbackHolder(CaptureCallback callback, List requestList,
- Handler handler, boolean repeating, int sessionId) {
- if (callback == null || handler == null) {
+ Executor executor, boolean repeating, int sessionId) {
+ if (callback == null || executor == null) {
throw new UnsupportedOperationException(
"Must have a valid handler and a valid callback");
}
mRepeating = repeating;
- mHandler = handler;
+ mExecutor = executor;
mRequestList = new ArrayList(requestList);
mCallback = callback;
mSessionId = sessionId;
@@ -1425,8 +1438,8 @@ public class CameraDeviceImpl extends CameraDevice
return getRequest(0);
}
- public Handler getHandler() {
- return mHandler;
+ public Executor getExecutor() {
+ return mExecutor;
}
public int getSessionId() {
@@ -1810,7 +1823,12 @@ public class CameraDeviceImpl extends CameraDevice
}
}
};
- holder.getHandler().post(resultDispatch);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ holder.getExecutor().execute(resultDispatch);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
}
@@ -1861,7 +1879,7 @@ public class CameraDeviceImpl extends CameraDevice
private void scheduleNotifyError(int code) {
mInError = true;
CameraDeviceImpl.this.mDeviceHandler.post(obtainRunnable(
- CameraDeviceCallbacks::notifyError, this, code));
+ CameraDeviceCallbacks::notifyError, this, code));
}
private void notifyError(int code) {
@@ -1929,36 +1947,41 @@ public class CameraDeviceImpl extends CameraDevice
if (isClosed()) return;
// Dispatch capture start notice
- holder.getHandler().post(
- new Runnable() {
- @Override
- public void run() {
- if (!CameraDeviceImpl.this.isClosed()) {
- final int subsequenceId = resultExtras.getSubsequenceId();
- final CaptureRequest request = holder.getRequest(subsequenceId);
-
- if (holder.hasBatchedOutputs()) {
- // Send derived onCaptureStarted for requests within the batch
- final Range fpsRange =
- request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
- for (int i = 0; i < holder.getRequestCount(); i++) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ holder.getExecutor().execute(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (!CameraDeviceImpl.this.isClosed()) {
+ final int subsequenceId = resultExtras.getSubsequenceId();
+ final CaptureRequest request = holder.getRequest(subsequenceId);
+
+ if (holder.hasBatchedOutputs()) {
+ // Send derived onCaptureStarted for requests within the
+ // batch
+ final Range fpsRange =
+ request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
+ for (int i = 0; i < holder.getRequestCount(); i++) {
+ holder.getCallback().onCaptureStarted(
+ CameraDeviceImpl.this,
+ holder.getRequest(i),
+ timestamp - (subsequenceId - i) *
+ NANO_PER_SECOND/fpsRange.getUpper(),
+ frameNumber - (subsequenceId - i));
+ }
+ } else {
holder.getCallback().onCaptureStarted(
CameraDeviceImpl.this,
- holder.getRequest(i),
- timestamp - (subsequenceId - i) *
- NANO_PER_SECOND/fpsRange.getUpper(),
- frameNumber - (subsequenceId - i));
+ holder.getRequest(resultExtras.getSubsequenceId()),
+ timestamp, frameNumber);
}
- } else {
- holder.getCallback().onCaptureStarted(
- CameraDeviceImpl.this,
- holder.getRequest(resultExtras.getSubsequenceId()),
- timestamp, frameNumber);
}
}
- }
- });
-
+ });
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
@@ -2111,7 +2134,12 @@ public class CameraDeviceImpl extends CameraDevice
finalResult = resultAsCapture;
}
- holder.getHandler().post(resultDispatch);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ holder.getExecutor().execute(resultDispatch);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
// Collect the partials for a total result; or mark the frame as totally completed
mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult,
@@ -2207,7 +2235,12 @@ public class CameraDeviceImpl extends CameraDevice
}
};
// Dispatch the failure callback
- holder.getHandler().post(failureDispatch);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ holder.getExecutor().execute(failureDispatch);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
} else {
boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
@@ -2247,13 +2280,49 @@ public class CameraDeviceImpl extends CameraDevice
checkAndFireSequenceComplete();
// Dispatch the failure callback
- holder.getHandler().post(failureDispatch);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ holder.getExecutor().execute(failureDispatch);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
} // public class CameraDeviceCallbacks
+ /**
+ * Instantiate a new Executor.
+ *
+ *
If the callback isn't null, check the handler and instantiate a new executor,
+ * otherwise instantiate a new executor in case handler is valid.
+ * If handler is null, get the current thread's
+ * Looper to create a Executor with. If no looper exists, throw
+ * {@code IllegalArgumentException}.
+ *
+ */
+ static Executor checkAndWrapHandler(Handler handler) {
+ return new HandlerExecutor(checkHandler(handler));
+ }
+
/**
* Default handler management.
*
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index a79a6c17f92..7bdb4a2f133 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -17,10 +17,10 @@
package android.hardware.camera2.params;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.IntDef;
-import android.os.Handler;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
@@ -31,6 +31,7 @@ import android.hardware.camera2.params.OutputConfiguration;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
+import java.util.concurrent.Executor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -78,7 +79,7 @@ public final class SessionConfiguration {
private List mOutputConfigurations;
private CameraCaptureSession.StateCallback mStateCallback;
private int mSessionType;
- private Handler mHandler = null;
+ private Executor mExecutor = null;
private InputConfiguration mInputConfig = null;
private CaptureRequest mSessionParameters = null;
@@ -87,10 +88,9 @@ public final class SessionConfiguration {
*
* @param sessionType The session type.
* @param outputs A list of output configurations for the capture session.
+ * @param executor The executor which should be used to invoke the callback. In general it is
+ * recommended that camera operations are not done on the main (UI) thread.
* @param cb A state callback interface implementation.
- * @param handler The handler on which the callback will be invoked. If it is
- * set to null, the callback will be invoked on the current thread's
- * {@link android.os.Looper looper}.
*
* @see #SESSION_REGULAR
* @see #SESSION_HIGH_SPEED
@@ -101,11 +101,12 @@ public final class SessionConfiguration {
*/
public SessionConfiguration(@SessionMode int sessionType,
@NonNull List outputs,
- @NonNull CameraCaptureSession.StateCallback cb, @Nullable Handler handler) {
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull CameraCaptureSession.StateCallback cb) {
mSessionType = sessionType;
mOutputConfigurations = Collections.unmodifiableList(new ArrayList<>(outputs));
mStateCallback = cb;
- mHandler = handler;
+ mExecutor = executor;
}
/**
@@ -136,14 +137,12 @@ public final class SessionConfiguration {
}
/**
- * Retrieve the {@link CameraCaptureSession.StateCallback} for the capture session.
+ * Retrieve the {@link java.util.concurrent.Executor} for the capture session.
*
- * @return The handler on which the callback will be invoked. If it is
- * set to null, the callback will be invoked on the current thread's
- * {@link android.os.Looper looper}.
+ * @return The Executor on which the callback will be invoked.
*/
- public Handler getHandler() {
- return mHandler;
+ public Executor getExecutor() {
+ return mExecutor;
}
/**
diff --git a/core/java/android/hardware/camera2/utils/TaskDrainer.java b/core/java/android/hardware/camera2/utils/TaskDrainer.java
index ed30ff34afc..e71f26a1879 100644
--- a/core/java/android/hardware/camera2/utils/TaskDrainer.java
+++ b/core/java/android/hardware/camera2/utils/TaskDrainer.java
@@ -15,11 +15,11 @@
*/
package android.hardware.camera2.utils;
-import android.os.Handler;
import android.util.Log;
import java.util.HashSet;
import java.util.Set;
+import java.util.concurrent.Executor;
import static com.android.internal.util.Preconditions.*;
@@ -55,7 +55,7 @@ public class TaskDrainer {
private static final String TAG = "TaskDrainer";
private final boolean DEBUG = false;
- private final Handler mHandler;
+ private final Executor mExecutor;
private final DrainListener mListener;
private final String mName;
@@ -73,28 +73,27 @@ public class TaskDrainer {
/**
* Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
- * via the {@code handler}.
+ * via the {@code executor}.
*
- * @param handler a non-{@code null} handler to use to post runnables to
+ * @param executor a non-{@code null} executor to use for listener execution
* @param listener a non-{@code null} listener where {@code onDrained} will be called
*/
- public TaskDrainer(Handler handler, DrainListener listener) {
- mHandler = checkNotNull(handler, "handler must not be null");
+ public TaskDrainer(Executor executor, DrainListener listener) {
+ mExecutor = checkNotNull(executor, "executor must not be null");
mListener = checkNotNull(listener, "listener must not be null");
mName = null;
}
/**
* Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
- * via the {@code handler}.
+ * via the {@code executor}.
*
- * @param handler a non-{@code null} handler to use to post runnables to
+ * @param executor a non-{@code null} executor to use for listener execution
* @param listener a non-{@code null} listener where {@code onDrained} will be called
* @param name an optional name used for debug logging
*/
- public TaskDrainer(Handler handler, DrainListener listener, String name) {
- // XX: Probably don't need a handler at all here
- mHandler = checkNotNull(handler, "handler must not be null");
+ public TaskDrainer(Executor executor, DrainListener listener, String name) {
+ mExecutor = checkNotNull(executor, "executor must not be null");
mListener = checkNotNull(listener, "listener must not be null");
mName = name;
}
@@ -200,15 +199,12 @@ public class TaskDrainer {
}
private void postDrained() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
+ mExecutor.execute(() -> {
if (DEBUG) {
Log.v(TAG + "[" + mName + "]", "onDrained");
}
mListener.onDrained();
- }
});
}
}
diff --git a/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java b/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java
index f6272c9e6a6..9615450be44 100644
--- a/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java
+++ b/core/java/android/hardware/camera2/utils/TaskSingleDrainer.java
@@ -16,7 +16,8 @@
package android.hardware.camera2.utils;
import android.hardware.camera2.utils.TaskDrainer.DrainListener;
-import android.os.Handler;
+
+import java.util.concurrent.Executor;
/**
* Keep track of a single concurrent task starting and finishing;
@@ -38,25 +39,25 @@ public class TaskSingleDrainer {
/**
* Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
- * via the {@code handler}.
+ * via the {@code executor}.
*
- * @param handler a non-{@code null} handler to use to post runnables to
+ * @param executor a non-{@code null} executor to use for listener execution
* @param listener a non-{@code null} listener where {@code onDrained} will be called
*/
- public TaskSingleDrainer(Handler handler, DrainListener listener) {
- mTaskDrainer = new TaskDrainer<>(handler, listener);
+ public TaskSingleDrainer(Executor executor, DrainListener listener) {
+ mTaskDrainer = new TaskDrainer<>(executor, listener);
}
/**
* Create a new task drainer; {@code onDrained} callbacks will be posted to the listener
- * via the {@code handler}.
+ * via the {@code executor}.
*
- * @param handler a non-{@code null} handler to use to post runnables to
+ * @param executor a non-{@code null} executor to use for listener execution
* @param listener a non-{@code null} listener where {@code onDrained} will be called
* @param name an optional name used for debug logging
*/
- public TaskSingleDrainer(Handler handler, DrainListener listener, String name) {
- mTaskDrainer = new TaskDrainer<>(handler, listener, name);
+ public TaskSingleDrainer(Executor executor, DrainListener listener, String name) {
+ mTaskDrainer = new TaskDrainer<>(executor, listener, name);
}
/**
--
GitLab
From 56bc6d0a479077cd4613f6deeec8be00910c24d3 Mon Sep 17 00:00:00 2001
From: Ivan Podogov
Date: Mon, 26 Feb 2018 16:04:24 +0000
Subject: [PATCH 005/488] Avoid changing display power state on draw wake lock
When Sidekick is controlling the display, any draw wake lock can cause a
sequence of endDisplayControl/setDisplayPowerState/beginDisplayControl
twice, because of DOZE_SUSPEND -> DOZE -> DOZE_SUSPEND transitions.
We can avoid that by telling power manager that display is controlled by
Sidekick, and draw wake locks shouldn't change the display power state.
Bug: 70574675
Test: build, flash Sardine, run Stopwatch, observe logcat
Change-Id: Ie4dac76606e45f0d3b62bc5890841f4f24d454d7
---
.../java/android/os/PowerManagerInternal.java | 8 ++++++
.../android/server/powermanagerservice.proto | 2 ++
.../server/power/PowerManagerService.java | 26 ++++++++++++++++++-
3 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index c7d89b0c6e4..2cb5aeeeb2e 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -141,6 +141,14 @@ public abstract class PowerManagerInternal {
public abstract void setDozeOverrideFromDreamManager(
int screenState, int screenBrightness);
+ /**
+ * Used by sidekick manager to tell the power manager if it shouldn't change the display state
+ * when a draw wake lock is acquired. Some processes may grab such a wake lock to do some work
+ * in a powered-up state, but we shouldn't give up sidekick control over the display until this
+ * override is lifted.
+ */
+ public abstract void setDrawWakeLockOverrideFromSidekick(boolean keepState);
+
public abstract PowerSaveState getLowPowerState(int serviceType);
public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index 5cb5319f4fe..64aa98b1136 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -315,4 +315,6 @@ message PowerServiceSettingsAndConfigurationDumpProto {
optional bool is_double_tap_wake_enabled = 37;
// True if we are currently in VR Mode.
optional bool is_vr_mode_enabled = 38;
+ // True if Sidekick is controlling the display and we shouldn't change its power mode.
+ optional bool draw_wake_lock_override_from_sidekick = 39;
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index f77b0ee5924..9cbde9de165 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -488,6 +488,9 @@ public final class PowerManagerService extends SystemService
// The screen brightness to use while dozing.
private int mDozeScreenBrightnessOverrideFromDreamManager = PowerManager.BRIGHTNESS_DEFAULT;
+ // Keep display state when dozing.
+ private boolean mDrawWakeLockOverrideFromSidekick;
+
// Time when we last logged a warning about calling userActivity() without permission.
private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE;
@@ -2424,7 +2427,8 @@ public final class PowerManagerService extends SystemService
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
- if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
+ if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0
+ && !mDrawWakeLockOverrideFromSidekick) {
if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
}
@@ -3176,6 +3180,16 @@ public final class PowerManagerService extends SystemService
}
}
+ private void setDrawWakeLockOverrideFromSidekickInternal(boolean keepState) {
+ synchronized (mLock) {
+ if (mDrawWakeLockOverrideFromSidekick != keepState) {
+ mDrawWakeLockOverrideFromSidekick = keepState;
+ mDirty |= DIRTY_SETTINGS;
+ updatePowerStateLocked();
+ }
+ }
+ }
+
@VisibleForTesting
void setVrModeEnabled(boolean enabled) {
mIsVrModeEnabled = enabled;
@@ -3381,6 +3395,7 @@ public final class PowerManagerService extends SystemService
+ mUserInactiveOverrideFromWindowManager);
pw.println(" mDozeScreenStateOverrideFromDreamManager="
+ mDozeScreenStateOverrideFromDreamManager);
+ pw.println(" mDrawWakeLockOverrideFromSidekick=" + mDrawWakeLockOverrideFromSidekick);
pw.println(" mDozeScreenBrightnessOverrideFromDreamManager="
+ mDozeScreenBrightnessOverrideFromDreamManager);
pw.println(" mScreenBrightnessSettingMinimum=" + mScreenBrightnessSettingMinimum);
@@ -3715,6 +3730,10 @@ public final class PowerManagerService extends SystemService
PowerServiceSettingsAndConfigurationDumpProto
.DOZE_SCREEN_STATE_OVERRIDE_FROM_DREAM_MANAGER,
mDozeScreenStateOverrideFromDreamManager);
+ proto.write(
+ PowerServiceSettingsAndConfigurationDumpProto
+ .DRAW_WAKE_LOCK_OVERRIDE_FROM_SIDEKICK,
+ mDrawWakeLockOverrideFromSidekick);
proto.write(
PowerServiceSettingsAndConfigurationDumpProto
.DOZED_SCREEN_BRIGHTNESS_OVERRIDE_FROM_DREAM_MANAGER,
@@ -4702,6 +4721,11 @@ public final class PowerManagerService extends SystemService
setUserActivityTimeoutOverrideFromWindowManagerInternal(timeoutMillis);
}
+ @Override
+ public void setDrawWakeLockOverrideFromSidekick(boolean keepState) {
+ setDrawWakeLockOverrideFromSidekickInternal(keepState);
+ }
+
@Override
public void setMaximumScreenOffTimeoutFromDeviceAdmin(@UserIdInt int userId, long timeMs) {
setMaximumScreenOffTimeoutFromDeviceAdminInternal(userId, timeMs);
--
GitLab
From 09da25f00d0d8cd6625b6ba6f184d4a182b04e7f Mon Sep 17 00:00:00 2001
From: Beverly
Date: Mon, 26 Feb 2018 09:17:07 -0500
Subject: [PATCH 006/488] Using zen duration preference
Test: make ROBOTEST_FILTER=ZenDurationDialogTest RunSettingsLibRoboTests -j40
Bug: 73741459
Change-Id: Ide76ac8016b84f128c47ad3731eeced25dce8c73
---
core/java/android/provider/Settings.java | 18 +-
core/proto/android/providers/settings.proto | 4 +-
core/res/res/values/strings.xml | 4 +-
.../res/layout/zen_mode_duration_dialog.xml | 52 +++
packages/SettingsLib/res/values/strings.xml | 11 +-
.../notification/ZenDurationDialog.java | 321 ++++++++++++++++++
.../notification/ZenDurationDialogTest.java | 222 ++++++++++++
.../SettingsProvider/res/values/defaults.xml | 7 +
.../settings/SettingsProtoDumpUtil.java | 3 +
.../providers/settings/SettingsProvider.java | 16 +-
.../android/systemui/qs/tiles/DndTile.java | 34 +-
proto/src/metrics_constants.proto | 1 -
12 files changed, 676 insertions(+), 17 deletions(-)
create mode 100644 packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml
create mode 100644 packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java
create mode 100644 packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bd29d2de7ba..a14f8ef5066 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11167,6 +11167,20 @@ public final class Settings {
*/
public static final String ZEN_MODE_CONFIG_ETAG = "zen_mode_config_etag";
+ /**
+ * If 0, turning on dnd manually will last indefinitely.
+ * Else if non-negative, turning on dnd manually will last for this many minutes.
+ * Else (if negative), turning on dnd manually will surface a dialog that prompts
+ * user to specify a duration.
+ * @hide
+ */
+ public static final String ZEN_DURATION = "zen_duration";
+
+ private static final Validator ZEN_DURATION_VALIDATOR = ANY_INTEGER_VALIDATOR;
+
+ /** @hide */ public static final int ZEN_DURATION_PROMPT = -1;
+ /** @hide */ public static final int ZEN_DURATION_FOREVER = 0;
+
/**
* Defines global heads up toggle. One of HEADS_UP_OFF, HEADS_UP_ON.
*
@@ -11541,7 +11555,8 @@ public final class Settings {
BLUETOOTH_ON,
PRIVATE_DNS_MODE,
PRIVATE_DNS_SPECIFIER,
- SOFT_AP_TIMEOUT_ENABLED
+ SOFT_AP_TIMEOUT_ENABLED,
+ ZEN_DURATION,
};
/**
@@ -11580,6 +11595,7 @@ public final class Settings {
VALIDATORS.put(WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON,
WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR);
VALIDATORS.put(APP_AUTO_RESTRICTION_ENABLED, APP_AUTO_RESTRICTION_ENABLED_VALIDATOR);
+ VALIDATORS.put(ZEN_DURATION, ZEN_DURATION_VALIDATOR);
}
/**
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index d7ba421ec3c..914a7db56f1 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -433,9 +433,11 @@ message GlobalSettingsProto {
optional SettingProto show_mute_in_crash_dialog = 352 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingsProto show_zen_upgrade_notification = 354 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingsProto app_auto_restriction_enabled = 359 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingsProto zen_duration = 360 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
// Please insert fields in the same order as in
// frameworks/base/core/java/android/provider/Settings.java.
- // Next tag = 360;
+ // Next tag = 361;
}
message SecureSettingsProto {
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 15dffc0ba52..9fb47429612 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4490,7 +4490,7 @@
- For one hour (until %2$s)
+ For 1 hour (until %2$s)For %1$d hours (until %2$s)
@@ -4514,7 +4514,7 @@
- For one hour
+ For 1 hourFor %d hours
diff --git a/packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml b/packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml
new file mode 100644
index 00000000000..6552296bc4e
--- /dev/null
+++ b/packages/SettingsLib/res/layout/zen_mode_duration_dialog.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 275cbc09e75..89af7f97ca5 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1062,10 +1062,13 @@
Less time.
-
- Turn onCancel
+
+ OK
+
+
+ Turn onTurn on Do Not Disturb
@@ -1083,4 +1086,8 @@
on %1$s
+
+ Duration
+
+ Ask every time
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java
new file mode 100644
index 00000000000..7369ba8c7f1
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.notification;
+
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.provider.Settings;
+import android.service.notification.Condition;
+import android.service.notification.ZenModeConfig;
+import android.support.annotation.VisibleForTesting;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.policy.PhoneWindow;
+import com.android.settingslib.R;
+
+import java.util.Arrays;
+
+public class ZenDurationDialog {
+ private static final int[] MINUTE_BUCKETS = ZenModeConfig.MINUTE_BUCKETS;
+ @VisibleForTesting protected static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
+ @VisibleForTesting protected static final int MAX_BUCKET_MINUTES =
+ MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
+ private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
+ @VisibleForTesting protected int mBucketIndex = -1;
+
+ @VisibleForTesting protected static final int FOREVER_CONDITION_INDEX = 0;
+ @VisibleForTesting protected static final int COUNTDOWN_CONDITION_INDEX = 1;
+ @VisibleForTesting protected static final int ALWAYS_ASK_CONDITION_INDEX = 2;
+
+ @VisibleForTesting protected Context mContext;
+ @VisibleForTesting protected LinearLayout mZenRadioGroupContent;
+ private RadioGroup mZenRadioGroup;
+ private int MAX_MANUAL_DND_OPTIONS = 3;
+
+ @VisibleForTesting protected LayoutInflater mLayoutInflater;
+
+ public ZenDurationDialog(Context context) {
+ mContext = context;
+ }
+
+ public Dialog createDialog() {
+ int zenDuration = Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.ZEN_DURATION,
+ Settings.Global.ZEN_DURATION_FOREVER);
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(mContext)
+ .setTitle(R.string.zen_mode_duration_settings_title)
+ .setNegativeButton(R.string.cancel, null)
+ .setPositiveButton(R.string.okay,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ updateZenDuration(zenDuration);
+ }
+ });
+
+ View contentView = getContentView();
+ setupRadioButtons(zenDuration);
+ builder.setView(contentView);
+ return builder.create();
+ }
+
+ @VisibleForTesting
+ protected void updateZenDuration(int currZenDuration) {
+ final int checkedRadioButtonId = mZenRadioGroup.getCheckedRadioButtonId();
+
+ int newZenDuration = Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.ZEN_DURATION,
+ Settings.Global.ZEN_DURATION_FOREVER);
+ switch (checkedRadioButtonId) {
+ case FOREVER_CONDITION_INDEX:
+ newZenDuration = Settings.Global.ZEN_DURATION_FOREVER;
+ MetricsLogger.action(mContext,
+ MetricsProto.MetricsEvent.
+ NOTIFICATION_ZEN_MODE_DURATION_FOREVER);
+ break;
+ case COUNTDOWN_CONDITION_INDEX:
+ ConditionTag tag = getConditionTagAt(checkedRadioButtonId);
+ newZenDuration = tag.countdownZenDuration;
+ MetricsLogger.action(mContext,
+ MetricsProto.MetricsEvent.
+ NOTIFICATION_ZEN_MODE_DURATION_TIME,
+ newZenDuration);
+ break;
+ case ALWAYS_ASK_CONDITION_INDEX:
+ newZenDuration = Settings.Global.ZEN_DURATION_PROMPT;
+ MetricsLogger.action(mContext,
+ MetricsProto.MetricsEvent.
+ NOTIFICATION_ZEN_MODE_DURATION_PROMPT);
+ break;
+ }
+
+ if (currZenDuration != newZenDuration) {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.ZEN_DURATION, newZenDuration);
+ }
+ }
+
+ @VisibleForTesting
+ protected View getContentView() {
+ if (mLayoutInflater == null) {
+ mLayoutInflater = new PhoneWindow(mContext).getLayoutInflater();
+ }
+ View contentView = mLayoutInflater.inflate(R.layout.zen_mode_duration_dialog,
+ null);
+ ScrollView container = (ScrollView) contentView.findViewById(R.id.zen_duration_container);
+
+ mZenRadioGroup = container.findViewById(R.id.zen_radio_buttons);
+ mZenRadioGroupContent = container.findViewById(R.id.zen_radio_buttons_content);
+
+ for (int i = 0; i < MAX_MANUAL_DND_OPTIONS; i++) {
+ final View radioButton = mLayoutInflater.inflate(R.layout.zen_mode_radio_button,
+ mZenRadioGroup, false);
+ mZenRadioGroup.addView(radioButton);
+ radioButton.setId(i);
+
+ final View radioButtonContent = mLayoutInflater.inflate(R.layout.zen_mode_condition,
+ mZenRadioGroupContent, false);
+ radioButtonContent.setId(i + MAX_MANUAL_DND_OPTIONS);
+ mZenRadioGroupContent.addView(radioButtonContent);
+ }
+
+ return contentView;
+ }
+
+ @VisibleForTesting
+ protected void setupRadioButtons(int zenDuration) {
+ int checkedIndex = ALWAYS_ASK_CONDITION_INDEX;
+ if (zenDuration == 0) {
+ checkedIndex = FOREVER_CONDITION_INDEX;
+ } else if (zenDuration > 0) {
+ checkedIndex = COUNTDOWN_CONDITION_INDEX;
+ }
+
+ bindTag(zenDuration, mZenRadioGroupContent.getChildAt(FOREVER_CONDITION_INDEX),
+ FOREVER_CONDITION_INDEX);
+ bindTag(zenDuration, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
+ COUNTDOWN_CONDITION_INDEX);
+ bindTag(zenDuration, mZenRadioGroupContent.getChildAt(ALWAYS_ASK_CONDITION_INDEX),
+ ALWAYS_ASK_CONDITION_INDEX);
+ getConditionTagAt(checkedIndex).rb.setChecked(true);
+ }
+
+ private void bindTag(final int currZenDuration, final View row, final int rowIndex) {
+ final ConditionTag tag = row.getTag() != null ? (ConditionTag) row.getTag() :
+ new ConditionTag();
+ row.setTag(tag);
+
+ if (tag.rb == null) {
+ tag.rb = (RadioButton) mZenRadioGroup.getChildAt(rowIndex);
+ }
+
+ // if duration is set to forever or always prompt, then countdown time defaults to 1 hour
+ if (currZenDuration <= 0) {
+ tag.countdownZenDuration = MINUTE_BUCKETS[DEFAULT_BUCKET_INDEX];
+ } else {
+ tag.countdownZenDuration = currZenDuration;
+ }
+
+ tag.rb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ tag.rb.setChecked(true);
+ }
+ }
+ });
+
+ updateUi(tag, row, rowIndex);
+ }
+
+ @VisibleForTesting
+ protected ConditionTag getConditionTagAt(int index) {
+ return (ConditionTag) mZenRadioGroupContent.getChildAt(index).getTag();
+ }
+
+
+ private void setupUi(ConditionTag tag, View row) {
+ tag.lines = row.findViewById(android.R.id.content);
+ tag.line1 = (TextView) row.findViewById(android.R.id.text1);
+
+ // text2 is not used in zen duration dialog
+ row.findViewById(android.R.id.text2).setVisibility(View.GONE);
+
+ tag.lines.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ tag.rb.setChecked(true);
+ }
+ });
+ }
+
+ private void updateButtons(ConditionTag tag, View row, int rowIndex) {
+ // minus button
+ final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
+ button1.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onClickTimeButton(row, tag, false /*down*/, rowIndex);
+ }
+ });
+
+ // plus button
+ final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
+ button2.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onClickTimeButton(row, tag, true /*up*/, rowIndex);
+ }
+ });
+
+ final long time = tag.countdownZenDuration;
+ if (rowIndex == COUNTDOWN_CONDITION_INDEX) {
+ button1.setVisibility(View.VISIBLE);
+ button2.setVisibility(View.VISIBLE);
+
+ button1.setEnabled(time > MIN_BUCKET_MINUTES);
+ button2.setEnabled(tag.countdownZenDuration != MAX_BUCKET_MINUTES);
+
+ button1.setAlpha(button1.isEnabled() ? 1f : .5f);
+ button2.setAlpha(button2.isEnabled() ? 1f : .5f);
+ } else {
+ button1.setVisibility(View.GONE);
+ button2.setVisibility(View.GONE);
+ }
+ }
+
+ @VisibleForTesting
+ protected void updateUi(ConditionTag tag, View row, int rowIndex) {
+ if (tag.lines == null) {
+ setupUi(tag, row);
+ }
+
+ updateButtons(tag, row, rowIndex);
+
+ String radioContentText = "";
+ switch (rowIndex) {
+ case FOREVER_CONDITION_INDEX:
+ radioContentText = mContext.getString(
+ com.android.internal.R.string.zen_mode_forever);
+ break;
+ case COUNTDOWN_CONDITION_INDEX:
+ Condition condition = ZenModeConfig.toTimeCondition(mContext,
+ tag.countdownZenDuration, ActivityManager.getCurrentUser(), false);
+ radioContentText = condition.line1;
+ break;
+ case ALWAYS_ASK_CONDITION_INDEX:
+ radioContentText = mContext.getString(
+ R.string.zen_mode_duration_always_prompt_title);
+ break;
+ }
+
+ tag.line1.setText(radioContentText);
+ }
+
+ @VisibleForTesting
+ protected void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
+ int newDndTimeDuration = -1;
+ final int N = MINUTE_BUCKETS.length;
+ if (mBucketIndex == -1) {
+ // not on a known index, search for the next or prev bucket by time
+ final long time = tag.countdownZenDuration;
+ for (int i = 0; i < N; i++) {
+ int j = up ? i : N - 1 - i;
+ final int bucketMinutes = MINUTE_BUCKETS[j];
+ if (up && bucketMinutes > time || !up && bucketMinutes < time) {
+ mBucketIndex = j;
+ newDndTimeDuration = bucketMinutes;
+ break;
+ }
+ }
+ if (newDndTimeDuration == -1) {
+ mBucketIndex = DEFAULT_BUCKET_INDEX;
+ newDndTimeDuration = MINUTE_BUCKETS[mBucketIndex];
+ }
+ } else {
+ // on a known index, simply increment or decrement
+ mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
+ newDndTimeDuration = MINUTE_BUCKETS[mBucketIndex];
+ }
+ tag.countdownZenDuration = newDndTimeDuration;
+ bindTag(newDndTimeDuration, row, rowId);
+ tag.rb.setChecked(true);
+ }
+
+ // used as the view tag on condition rows
+ @VisibleForTesting
+ protected static class ConditionTag {
+ public RadioButton rb;
+ public View lines;
+ public TextView line1;
+ public int countdownZenDuration; // only important for countdown radio button
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java
new file mode 100644
index 00000000000..9b491c200cd
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyObject;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.ContentResolver;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.provider.Settings;
+import android.service.notification.Condition;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class ZenDurationDialogTest {
+ private ZenDurationDialog mController;
+
+ private Context mContext;
+ private LayoutInflater mLayoutInflater;
+ private Condition mCountdownCondition;
+ private Condition mAlarmCondition;
+ private ContentResolver mContentResolver;
+
+ @Before
+ public void setup() {
+ mContext = RuntimeEnvironment.application;
+ mContentResolver = RuntimeEnvironment.application.getContentResolver();
+ mLayoutInflater = LayoutInflater.from(mContext);
+
+ mController = spy(new ZenDurationDialog(mContext));
+ mController.mLayoutInflater = mLayoutInflater;
+ mController.getContentView();
+ }
+
+ @Test
+ public void testAlwaysPrompt() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+ Settings.Global.ZEN_DURATION_PROMPT);
+ mController.createDialog();
+
+ assertFalse(mController.getConditionTagAt(ZenDurationDialog.FOREVER_CONDITION_INDEX).rb
+ .isChecked());
+ assertFalse(mController.getConditionTagAt(ZenDurationDialog.COUNTDOWN_CONDITION_INDEX).rb
+ .isChecked());
+ assertTrue(mController.getConditionTagAt(
+ ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.isChecked());
+ }
+
+ @Test
+ public void testForever() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+ Settings.Global.ZEN_DURATION_FOREVER);
+ mController.createDialog();
+
+ assertTrue(mController.getConditionTagAt(ZenDurationDialog.FOREVER_CONDITION_INDEX).rb
+ .isChecked());
+ assertFalse(mController.getConditionTagAt(ZenDurationDialog.COUNTDOWN_CONDITION_INDEX).rb
+ .isChecked());
+ assertFalse(mController.getConditionTagAt(
+ ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.isChecked());
+ }
+
+ @Test
+ public void testSpecificDuration() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION, 45);
+ mController.createDialog();
+
+ assertFalse(mController.getConditionTagAt(ZenDurationDialog.FOREVER_CONDITION_INDEX).rb
+ .isChecked());
+ assertTrue(mController.getConditionTagAt(ZenDurationDialog.COUNTDOWN_CONDITION_INDEX).rb
+ .isChecked());
+ assertFalse(mController.getConditionTagAt(
+ ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.isChecked());
+ }
+
+
+ @Test
+ public void testChooseAlwaysPromptSetting() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+ Settings.Global.ZEN_DURATION_FOREVER);
+
+ AlertDialog dialog = (AlertDialog) mController.createDialog();
+ mController.getConditionTagAt(ZenDurationDialog.ALWAYS_ASK_CONDITION_INDEX).rb.setChecked(
+ true);
+ mController.updateZenDuration(Settings.Global.ZEN_DURATION_FOREVER);
+
+ assertEquals(Settings.Global.ZEN_DURATION_PROMPT, Settings.Global.getInt(mContentResolver,
+ Settings.Global.ZEN_DURATION, Settings.Global.ZEN_DURATION_FOREVER));
+ }
+
+ @Test
+ public void testChooseForeverSetting() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+ Settings.Global.ZEN_DURATION_PROMPT);
+
+ AlertDialog dialog = (AlertDialog) mController.createDialog();
+ mController.getConditionTagAt(ZenDurationDialog.FOREVER_CONDITION_INDEX).rb.setChecked(
+ true);
+ mController.updateZenDuration(Settings.Global.ZEN_DURATION_PROMPT);
+
+ assertEquals(Settings.Global.ZEN_DURATION_FOREVER, Settings.Global.getInt(mContentResolver,
+ Settings.Global.ZEN_DURATION, Settings.Global.ZEN_DURATION_PROMPT));
+ }
+
+ @Test
+ public void testChooseTimeSetting() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+ Settings.Global.ZEN_DURATION_PROMPT);
+
+ AlertDialog dialog = (AlertDialog) mController.createDialog();
+ mController.getConditionTagAt(ZenDurationDialog.COUNTDOWN_CONDITION_INDEX).rb.setChecked(
+ true);
+ mController.updateZenDuration(Settings.Global.ZEN_DURATION_PROMPT);
+
+ // countdown defaults to 60 minutes:
+ assertEquals(60, Settings.Global.getInt(mContentResolver,
+ Settings.Global.ZEN_DURATION, Settings.Global.ZEN_DURATION_PROMPT));
+ }
+
+ @Test
+ public void testGetTimeFromBucket() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.ZEN_DURATION,
+ Settings.Global.ZEN_DURATION_PROMPT);
+
+ AlertDialog dialog = (AlertDialog) mController.createDialog();
+ // click time button starts at 60 minutes
+ // - 1 hour to MAX_BUCKET_MINUTES (12 hours), increments by 1 hour
+ // - 0-60 minutes increments by 15 minutes
+ View view = mController.mZenRadioGroupContent.getChildAt(
+ ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+ ZenDurationDialog.ConditionTag tag = mController.getConditionTagAt(
+ ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+
+ // test incrementing up:
+ mController.onClickTimeButton(view, tag, true, ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+ assertEquals(120, tag.countdownZenDuration); // goes from 1 hour to 2 hours
+
+ // try clicking up 50 times - should max out at ZenDurationDialog.MAX_BUCKET_MINUTES
+ for (int i = 0; i < 50; i++) {
+ mController.onClickTimeButton(view, tag, true,
+ ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+ }
+ assertEquals(ZenDurationDialog.MAX_BUCKET_MINUTES, tag.countdownZenDuration);
+
+ // reset, test incrementing down:
+ mController.mBucketIndex = -1; // reset current bucket index to reset countdownZenDuration
+ tag.countdownZenDuration = 60; // back to default
+ mController.onClickTimeButton(view, tag, false,
+ ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+ assertEquals(45, tag.countdownZenDuration); // goes from 60 minutes to 45 minutes
+
+ // try clicking down 50 times - should stop at MIN_BUCKET_MINUTES
+ for (int i = 0; i < 50; i++) {
+ mController.onClickTimeButton(view, tag, false,
+ ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+ }
+ assertEquals(ZenDurationDialog.MIN_BUCKET_MINUTES, tag.countdownZenDuration);
+
+ // reset countdownZenDuration to unbucketed number, should round change to nearest bucket
+ mController.mBucketIndex = -1;
+ tag.countdownZenDuration = 50;
+ mController.onClickTimeButton(view, tag, false,
+ ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+ assertEquals(45, tag.countdownZenDuration);
+
+ mController.mBucketIndex = -1;
+ tag.countdownZenDuration = 50;
+ mController.onClickTimeButton(view, tag, true,
+ ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+ assertEquals(60, tag.countdownZenDuration);
+
+ mController.mBucketIndex = -1;
+ tag.countdownZenDuration = 75;
+ mController.onClickTimeButton(view, tag, false,
+ ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+ assertEquals(60, tag.countdownZenDuration);
+
+ mController.mBucketIndex = -1;
+ tag.countdownZenDuration = 75;
+ mController.onClickTimeButton(view, tag, true,
+ ZenDurationDialog.COUNTDOWN_CONDITION_INDEX);
+ assertEquals(120, tag.countdownZenDuration);
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index c173225be5c..1cd02f41835 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -200,4 +200,11 @@
+
+
+ 0
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 11c869f49ac..ccb4d8c866d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1141,6 +1141,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.APP_AUTO_RESTRICTION_ENABLED,
GlobalSettingsProto.APP_AUTO_RESTRICTION_ENABLED);
+ dumpSetting(s, p,
+ Settings.Global.ZEN_DURATION,
+ GlobalSettingsProto.ZEN_DURATION);
// Please insert new settings using the same order as in Settings.Global.
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index baf17cb0c46..63988584790 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2938,7 +2938,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 156;
+ private static final int SETTINGS_VERSION = 157;
private final int mUserId;
@@ -3604,7 +3604,21 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 156;
}
+ if (currentVersion == 156) {
+ // Version 156: Set a default value for zen duration
+ final SettingsState globalSettings = getGlobalSettingsLocked();
+ final Setting currentSetting = globalSettings.getSettingLocked(
+ Global.ZEN_DURATION);
+ if (currentSetting.isNull()) {
+ String defaultZenDuration = Integer.toString(getContext()
+ .getResources().getInteger(R.integer.def_zen_duration));
+ globalSettings.insertSettingLocked(
+ Global.ZEN_DURATION, defaultZenDuration,
+ null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ currentVersion = 157;
+ }
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 2d31669db6c..f3a2ae3770b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -19,6 +19,7 @@ package com.android.systemui.qs.tiles;
import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
import static android.provider.Settings.Global.ZEN_MODE_OFF;
+import android.app.ActivityManager;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -28,6 +29,7 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.net.Uri;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Global;
@@ -139,15 +141,29 @@ public class DndTile extends QSTileImpl {
@Override
public void showDetail(boolean show) {
- mUiHandler.post(() -> {
- Dialog mDialog = new EnableZenModeDialog(mContext).createDialog();
- mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- SystemUIDialog.setShowForAllUsers(mDialog, true);
- SystemUIDialog.registerDismissListener(mDialog);
- SystemUIDialog.setWindowOnTop(mDialog);
- mUiHandler.post(() -> mDialog.show());
- mHost.collapsePanels();
- });
+ int zenDuration = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.ZEN_DURATION, 0);
+ switch (zenDuration) {
+ case Settings.Global.ZEN_DURATION_PROMPT:
+ mUiHandler.post(() -> {
+ Dialog mDialog = new EnableZenModeDialog(mContext).createDialog();
+ mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ SystemUIDialog.setShowForAllUsers(mDialog, true);
+ SystemUIDialog.registerDismissListener(mDialog);
+ SystemUIDialog.setWindowOnTop(mDialog);
+ mUiHandler.post(() -> mDialog.show());
+ mHost.collapsePanels();
+ });
+ break;
+ case Settings.Global.ZEN_DURATION_FOREVER:
+ mController.setZen(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG);
+ break;
+ default:
+ Uri conditionId = ZenModeConfig.toTimeCondition(mContext, zenDuration,
+ ActivityManager.getCurrentUser(), true).id;
+ mController.setZen(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ conditionId, TAG);
+ }
}
@Override
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index e962c0b23f9..e7e765dcde9 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5363,7 +5363,6 @@ message MetricsEvent {
// OS: P
ACTION_PANEL_VIEW_EXPAND = 1328;
-
// FIELD: Rotation of the device
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: P
--
GitLab
From e536bf7b22b35ddebb58d2451533b75d825113e7 Mon Sep 17 00:00:00 2001
From: Chong Zhang
Date: Tue, 6 Mar 2018 15:47:54 -0800
Subject: [PATCH 007/488] heif: add definition for HEVC Main Still Picture
profile
Add corresponding def to OMX for HEVC Main Still Picture.
bug: 63633199
Change-Id: I2d968f5871e3afcd08758c2d5e1452b6c13d0862
---
api/current.txt | 1 +
media/java/android/media/MediaCodecInfo.java | 1 +
2 files changed, 2 insertions(+)
diff --git a/api/current.txt b/api/current.txt
index 2113d5d54f5..b9dc87fb178 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23249,6 +23249,7 @@ package android.media {
field public static final int HEVCProfileMain = 1; // 0x1
field public static final int HEVCProfileMain10 = 2; // 0x2
field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
+ field public static final int HEVCProfileMainStill = 4; // 0x4
field public static final int MPEG2LevelH14 = 2; // 0x2
field public static final int MPEG2LevelHL = 3; // 0x3
field public static final int MPEG2LevelHP = 4; // 0x4
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 44d909972e3..9a6e8eb3c8a 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -3002,6 +3002,7 @@ public final class MediaCodecInfo {
// from OMX_VIDEO_HEVCPROFILETYPE
public static final int HEVCProfileMain = 0x01;
public static final int HEVCProfileMain10 = 0x02;
+ public static final int HEVCProfileMainStill = 0x04;
public static final int HEVCProfileMain10HDR10 = 0x1000;
// from OMX_VIDEO_HEVCLEVELTYPE
--
GitLab
From ef335260b2b884989df286cb9cb16f6031eca192 Mon Sep 17 00:00:00 2001
From: Felipe Leme
Date: Wed, 7 Mar 2018 11:49:44 -0800
Subject: [PATCH 008/488] Implemented WebView.isVisibleToUserForAutofill()
Bug: 73500079
Test: mmm -j35 frameworks/base/
Change-Id: I1a98d685f05cd6f2a8f7f62ffacd6c802557e5b6
---
api/system-current.txt | 1 +
core/java/android/webkit/WebView.java | 5 +++++
core/java/android/webkit/WebViewProvider.java | 13 ++++++++-----
3 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/api/system-current.txt b/api/system-current.txt
index 05552630909..742072030e1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6653,6 +6653,7 @@ package android.webkit {
method public abstract android.view.View findFocus(android.view.View);
method public abstract android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
method public abstract android.os.Handler getHandler(android.os.Handler);
+ method public default boolean isVisibleToUserForAutofill(int);
method public abstract void onActivityResult(int, int, android.content.Intent);
method public abstract void onAttachedToWindow();
method public abstract void onConfigurationChanged(android.content.res.Configuration);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index fadc3dc75e8..8149dc91ac2 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2906,6 +2906,11 @@ public class WebView extends AbsoluteLayout
mProvider.getViewDelegate().autofill(values);
}
+ @Override
+ public boolean isVisibleToUserForAutofill(int virtualId) {
+ return mProvider.getViewDelegate().isVisibleToUserForAutofill(virtualId);
+ }
+
/** @hide */
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index a8969252ff2..805cac0164b 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -329,13 +329,16 @@ public interface WebViewProvider {
public void onProvideVirtualStructure(android.view.ViewStructure structure);
- @SuppressWarnings("unused")
- public default void onProvideAutofillVirtualStructure(android.view.ViewStructure structure,
- int flags) {
+ default void onProvideAutofillVirtualStructure(
+ @SuppressWarnings("unused") android.view.ViewStructure structure,
+ @SuppressWarnings("unused") int flags) {
}
- @SuppressWarnings("unused")
- public default void autofill(SparseArrayvalues) {
+ default void autofill(@SuppressWarnings("unused") SparseArray values) {
+ }
+
+ default boolean isVisibleToUserForAutofill(@SuppressWarnings("unused") int virtualId) {
+ return true; // true is the default value returned by View.isVisibleToUserForAutofill()
}
public AccessibilityNodeProvider getAccessibilityNodeProvider();
--
GitLab
From 36abd8a6d662d4aa9256e91016c92217f8e12bc1 Mon Sep 17 00:00:00 2001
From: Yohei Yukawa
Date: Wed, 7 Mar 2018 19:14:47 -0800
Subject: [PATCH 009/488] Revert "Accept null subtype in
InputMethodSubtypeHandle."
This reverts commit 46ac35d09b0a1ba7af7eb4c14293a7978edcd2ab [1].
Reason for revert:
This is the part 1 of a series of reverts to unlaunch Bug 25752812,
which aimed to improve UX but did not work well.
See I7a2ed6dd39dcd8207d3d94e12cd01d5d67ba4bb5 for the detailed reason
of revert.
[1]: Ia013784a594ad3beaf30976d047f5ac0fa8185be
Bug: 66498367
Test: Manually done
Change-Id: Ifd17b53704b3dff75b6ef3be6835f51271859933
---
core/java/android/hardware/input/InputManager.java | 11 ++++-------
.../inputmethod/InputMethodSubtypeHandle.java | 5 ++---
.../com/android/server/input/InputManagerService.java | 4 ++--
3 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index fdea5a2f935..87895f7e612 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -17,7 +17,6 @@
package android.hardware.input;
import android.annotation.IntDef;
-import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
@@ -709,16 +708,14 @@ public final class InputManager {
*
* @param identifier The identifier for the input device.
* @param inputMethodInfo The input method.
- * @param inputMethodSubtype The input method subtype. {@code null} if this input method does
- * not support any subtype.
+ * @param inputMethodSubtype The input method subtype.
*
* @return The associated {@link KeyboardLayout}, or null if one has not been set.
*
* @hide
*/
- @Nullable
public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype) {
+ InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype) {
try {
return mIm.getKeyboardLayoutForInputDevice(
identifier, inputMethodInfo, inputMethodSubtype);
@@ -733,13 +730,13 @@ public final class InputManager {
* @param identifier The identifier for the input device.
* @param inputMethodInfo The input method with which to associate the keyboard layout.
* @param inputMethodSubtype The input method subtype which which to associate the keyboard
- * layout. {@code null} if this input method does not support any subtype.
+ * layout.
* @param keyboardLayoutDescriptor The descriptor of the keyboard layout to set
*
* @hide
*/
public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype,
+ InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype,
String keyboardLayoutDescriptor) {
try {
mIm.setKeyboardLayoutForInputDevice(identifier, inputMethodInfo,
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
index 04d7f9b2c9c..975021e85cc 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
@@ -16,7 +16,6 @@
package com.android.internal.inputmethod;
-import android.annotation.Nullable;
import android.text.TextUtils;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
@@ -27,12 +26,12 @@ public class InputMethodSubtypeHandle {
private final String mInputMethodId;
private final int mSubtypeId;
- public InputMethodSubtypeHandle(InputMethodInfo info, @Nullable InputMethodSubtype subtype) {
+ public InputMethodSubtypeHandle(InputMethodInfo info, InputMethodSubtype subtype) {
mInputMethodId = info.getId();
if (subtype != null) {
mSubtypeId = subtype.hashCode();
} else {
- mSubtypeId = InputMethodUtils.NOT_A_SUBTYPE_ID;
+ mSubtypeId = 0;
}
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index a951d470735..620f2ca3fc5 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1408,8 +1408,8 @@ public class InputManagerService extends IInputManager.Stub
if (keyboardLayoutDescriptor == null) {
throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
}
- if (imeInfo == null) {
- throw new IllegalArgumentException("imeInfo must not be null");
+ if (imeInfo == null || imeSubtype == null) {
+ throw new IllegalArgumentException("imeInfo and imeSubtype must not be null");
}
InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
--
GitLab
From 2d9accb29f8878cd6d92ec78d1956e64322bce5c Mon Sep 17 00:00:00 2001
From: Yohei Yukawa
Date: Wed, 7 Mar 2018 19:15:15 -0800
Subject: [PATCH 010/488] Revert "Switch and store keyboard layouts based on
IME subtype."
This reverts commit d5f7ed9fe9dc3590f6ef9cb7470e29e836a95907 [1].
Reason for revert:
This is the part 2 of a series of reverts to unlaunch Bug 25752812,
which aimed to improve UX but did not work well.
See I7a2ed6dd39dcd8207d3d94e12cd01d5d67ba4bb5 for the detailed reason
of revert.
[1]: Ie88ce1ab77dbfe03ab51d89c1dc9e0a7ddbb3216
Bug: 66498367
Test: Manually done
Change-Id: I207919e3cb081d77712371f58463a5d423717c8f
---
.../android/hardware/input/IInputManager.aidl | 7 -
.../android/hardware/input/InputManager.java | 46 ----
.../hardware/input/TouchCalibration.java | 6 -
.../inputmethod/InputMethodSubtypeHandle.java | 71 ------
.../server/input/InputManagerService.java | 220 ++++--------------
.../server/input/PersistentDataStore.java | 175 ++++----------
.../server/policy/PhoneWindowManager.java | 9 +
.../server/policy/WindowManagerPolicy.java | 6 +
.../server/wm/WindowManagerService.java | 6 +
9 files changed, 102 insertions(+), 444 deletions(-)
delete mode 100644 core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 9e0c680cafa..97868fa268a 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -26,8 +26,6 @@ import android.os.IBinder;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.PointerIcon;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
/** @hide */
interface IInputManager {
@@ -67,11 +65,6 @@ interface IInputManager {
String keyboardLayoutDescriptor);
void removeKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor);
- KeyboardLayout getKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
- in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype);
- void setKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
- in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype,
- String keyboardLayoutDescriptor);
// Registers an input devices changed listener.
void registerInputDevicesChangedListener(IInputDevicesChangedListener listener);
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 87895f7e612..6ae7a146a7b 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -42,8 +42,6 @@ import android.view.InputDevice;
import android.view.InputEvent;
import android.view.MotionEvent;
import android.view.PointerIcon;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.os.SomeArgs;
@@ -702,50 +700,6 @@ public final class InputManager {
}
}
-
- /**
- * Gets the keyboard layout for the specified input device and IME subtype.
- *
- * @param identifier The identifier for the input device.
- * @param inputMethodInfo The input method.
- * @param inputMethodSubtype The input method subtype.
- *
- * @return The associated {@link KeyboardLayout}, or null if one has not been set.
- *
- * @hide
- */
- public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype) {
- try {
- return mIm.getKeyboardLayoutForInputDevice(
- identifier, inputMethodInfo, inputMethodSubtype);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
- /**
- * Sets the keyboard layout for the specified input device and IME subtype pair.
- *
- * @param identifier The identifier for the input device.
- * @param inputMethodInfo The input method with which to associate the keyboard layout.
- * @param inputMethodSubtype The input method subtype which which to associate the keyboard
- * layout.
- * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to set
- *
- * @hide
- */
- public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype,
- String keyboardLayoutDescriptor) {
- try {
- mIm.setKeyboardLayoutForInputDevice(identifier, inputMethodInfo,
- inputMethodSubtype, keyboardLayoutDescriptor);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
-
/**
* Gets the TouchCalibration applied to the specified input device's coordinates.
*
diff --git a/core/java/android/hardware/input/TouchCalibration.java b/core/java/android/hardware/input/TouchCalibration.java
index 15503ed0b90..025fad046eb 100644
--- a/core/java/android/hardware/input/TouchCalibration.java
+++ b/core/java/android/hardware/input/TouchCalibration.java
@@ -123,10 +123,4 @@ public class TouchCalibration implements Parcelable {
Float.floatToIntBits(mYScale) ^
Float.floatToIntBits(mYOffset);
}
-
- @Override
- public String toString() {
- return String.format("[%f, %f, %f, %f, %f, %f]",
- mXScale, mXYMix, mXOffset, mYXMix, mYScale, mYOffset);
- }
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
deleted file mode 100644
index 975021e85cc..00000000000
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2016 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.inputmethod;
-
-import android.text.TextUtils;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
-
-import java.util.Objects;
-
-public class InputMethodSubtypeHandle {
- private final String mInputMethodId;
- private final int mSubtypeId;
-
- public InputMethodSubtypeHandle(InputMethodInfo info, InputMethodSubtype subtype) {
- mInputMethodId = info.getId();
- if (subtype != null) {
- mSubtypeId = subtype.hashCode();
- } else {
- mSubtypeId = 0;
- }
- }
-
- public InputMethodSubtypeHandle(String inputMethodId, int subtypeId) {
- mInputMethodId = inputMethodId;
- mSubtypeId = subtypeId;
- }
-
- public String getInputMethodId() {
- return mInputMethodId;
- }
-
- public int getSubtypeId() {
- return mSubtypeId;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == null || !(o instanceof InputMethodSubtypeHandle)) {
- return false;
- }
- InputMethodSubtypeHandle other = (InputMethodSubtypeHandle) o;
- return TextUtils.equals(mInputMethodId, other.getInputMethodId())
- && mSubtypeId == other.getSubtypeId();
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(mInputMethodId) * 31 + mSubtypeId;
- }
-
- @Override
- public String toString() {
- return "InputMethodSubtypeHandle{mInputMethodId=" + mInputMethodId
- + ", mSubtypeId=" + mSubtypeId + "}";
- }
-}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 620f2ca3fc5..a70909ff415 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -22,7 +22,6 @@ import android.os.LocaleList;
import android.os.ShellCallback;
import android.util.Log;
import android.view.Display;
-import com.android.internal.inputmethod.InputMethodSubtypeHandle;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
@@ -79,8 +78,6 @@ import android.os.Message;
import android.os.MessageQueue;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ShellCommand;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -101,6 +98,7 @@ import android.view.Surface;
import android.view.ViewConfiguration;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
+import android.widget.Toast;
import java.io.File;
import java.io.FileDescriptor;
@@ -174,7 +172,8 @@ public class InputManagerService extends IInputManager.Stub
private final ArrayList
mTempFullKeyboards = new ArrayList(); // handler thread only
private boolean mKeyboardLayoutNotificationShown;
- private InputMethodSubtypeHandle mCurrentImeHandle;
+ private PendingIntent mKeyboardLayoutIntent;
+ private Toast mSwitchedKeyboardLayoutToast;
// State for vibrator tokens.
private Object mVibratorLock = new Object();
@@ -1367,82 +1366,6 @@ public class InputManagerService extends IInputManager.Stub
}
}
- @Override // Binder call
- @Nullable
- public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- InputMethodInfo imeInfo, InputMethodSubtype imeSubtype) {
- InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
- String key = getLayoutDescriptor(identifier);
- final String keyboardLayoutDescriptor;
- synchronized (mDataStore) {
- keyboardLayoutDescriptor = mDataStore.getKeyboardLayout(key, handle);
- }
-
- if (keyboardLayoutDescriptor == null) {
- return null;
- }
-
- final KeyboardLayout[] result = new KeyboardLayout[1];
- visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
- @Override
- public void visitKeyboardLayout(Resources resources,
- int keyboardLayoutResId, KeyboardLayout layout) {
- result[0] = layout;
- }
- });
- if (result[0] == null) {
- Slog.w(TAG, "Could not get keyboard layout with descriptor '"
- + keyboardLayoutDescriptor + "'.");
- }
- return result[0];
- }
-
- @Override
- public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- InputMethodInfo imeInfo, InputMethodSubtype imeSubtype,
- String keyboardLayoutDescriptor) {
- if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
- "setKeyboardLayoutForInputDevice()")) {
- throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
- }
- if (keyboardLayoutDescriptor == null) {
- throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
- }
- if (imeInfo == null || imeSubtype == null) {
- throw new IllegalArgumentException("imeInfo and imeSubtype must not be null");
- }
- InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
- setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
- }
-
- private void setKeyboardLayoutForInputDeviceInner(InputDeviceIdentifier identifier,
- InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
- String key = getLayoutDescriptor(identifier);
- synchronized (mDataStore) {
- try {
- if (mDataStore.setKeyboardLayout(key, imeHandle, keyboardLayoutDescriptor)) {
- if (DEBUG) {
- Slog.d(TAG, "Set keyboard layout " + keyboardLayoutDescriptor +
- " for subtype " + imeHandle + " and device " + identifier +
- " using key " + key);
- }
- if (imeHandle.equals(mCurrentImeHandle)) {
- if (DEBUG) {
- Slog.d(TAG, "Layout for current subtype changed, switching layout");
- }
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = identifier;
- args.arg2 = imeHandle;
- mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, args).sendToTarget();
- }
- mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
- }
- } finally {
- mDataStore.saveIfNeeded();
- }
- }
- }
-
@Override // Binder call
public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
String keyboardLayoutDescriptor) {
@@ -1462,7 +1385,8 @@ public class InputManagerService extends IInputManager.Stub
oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
}
if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
- && !Objects.equals(oldLayout, mDataStore.getCurrentKeyboardLayout(key))) {
+ && !Objects.equals(oldLayout,
+ mDataStore.getCurrentKeyboardLayout(key))) {
mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
}
} finally {
@@ -1512,44 +1436,45 @@ public class InputManagerService extends IInputManager.Stub
Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
+ " ime=" + inputMethodInfo + " subtype=" + subtype);
}
- if (inputMethodInfo == null) {
- Slog.d(TAG, "No InputMethod is running, ignoring change");
- return;
- }
- if (subtype != null && !"keyboard".equals(subtype.getMode())) {
- Slog.d(TAG, "InputMethodSubtype changed to non-keyboard subtype, ignoring change");
- return;
- }
- InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(inputMethodInfo, subtype);
- if (!handle.equals(mCurrentImeHandle)) {
- mCurrentImeHandle = handle;
- handleSwitchKeyboardLayout(null, handle);
- }
+ }
+
+ public void switchKeyboardLayout(int deviceId, int direction) {
+ mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
}
// Must be called on handler.
- private void handleSwitchKeyboardLayout(@Nullable InputDeviceIdentifier identifier,
- InputMethodSubtypeHandle handle) {
- synchronized (mInputDevicesLock) {
- for (InputDevice device : mInputDevices) {
- if (identifier != null && !device.getIdentifier().equals(identifier) ||
- !device.isFullKeyboard()) {
- continue;
+ private void handleSwitchKeyboardLayout(int deviceId, int direction) {
+ final InputDevice device = getInputDevice(deviceId);
+ if (device != null) {
+ final boolean changed;
+ final String keyboardLayoutDescriptor;
+
+ String key = getLayoutDescriptor(device.getIdentifier());
+ synchronized (mDataStore) {
+ try {
+ changed = mDataStore.switchKeyboardLayout(key, direction);
+ keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
+ key);
+ } finally {
+ mDataStore.saveIfNeeded();
}
- String key = getLayoutDescriptor(device.getIdentifier());
- boolean changed = false;
- synchronized (mDataStore) {
- try {
- if (mDataStore.switchKeyboardLayout(key, handle)) {
- changed = true;
- }
- } finally {
- mDataStore.saveIfNeeded();
- }
+ }
+
+ if (changed) {
+ if (mSwitchedKeyboardLayoutToast != null) {
+ mSwitchedKeyboardLayoutToast.cancel();
+ mSwitchedKeyboardLayoutToast = null;
}
- if (changed) {
- reloadKeyboardLayouts();
+ if (keyboardLayoutDescriptor != null) {
+ KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
+ if (keyboardLayout != null) {
+ mSwitchedKeyboardLayoutToast = Toast.makeText(
+ mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
+ mSwitchedKeyboardLayoutToast.show();
+ }
}
+
+ reloadKeyboardLayouts();
}
}
}
@@ -1790,7 +1715,7 @@ public class InputManagerService extends IInputManager.Stub
}
@Override
- public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
pw.println("INPUT MANAGER (dumpsys input)\n");
@@ -1798,49 +1723,8 @@ public class InputManagerService extends IInputManager.Stub
if (dumpStr != null) {
pw.println(dumpStr);
}
- pw.println(" Keyboard Layouts:");
- visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
- @Override
- public void visitKeyboardLayout(Resources resources,
- int keyboardLayoutResId, KeyboardLayout layout) {
- pw.println(" \"" + layout + "\": " + layout.getDescriptor());
- }
- });
- pw.println();
- synchronized(mDataStore) {
- mDataStore.dump(pw, " ");
- }
}
- @Override
- public void onShellCommand(FileDescriptor in, FileDescriptor out,
- FileDescriptor err, String[] args, ShellCallback callback,
- ResultReceiver resultReceiver) {
- (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
- }
-
- public int onShellCommand(Shell shell, String cmd) {
- if (TextUtils.isEmpty(cmd)) {
- shell.onHelp();
- return 1;
- }
- if (cmd.equals("setlayout")) {
- if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
- "onShellCommand()")) {
- throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
- }
- InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
- shell.getNextArgRequired(), Integer.parseInt(shell.getNextArgRequired()));
- String descriptor = shell.getNextArgRequired();
- int vid = Integer.decode(shell.getNextArgRequired());
- int pid = Integer.decode(shell.getNextArgRequired());
- InputDeviceIdentifier id = new InputDeviceIdentifier(descriptor, vid, pid);
- setKeyboardLayoutForInputDeviceInner(id, handle, shell.getNextArgRequired());
- }
- return 0;
- }
-
-
private boolean checkCallingPermission(String permission, String func) {
// Quick check: if the calling permission is me, it's all okay.
if (Binder.getCallingPid() == Process.myPid()) {
@@ -2169,12 +2053,9 @@ public class InputManagerService extends IInputManager.Stub
case MSG_DELIVER_INPUT_DEVICES_CHANGED:
deliverInputDevicesChanged((InputDevice[])msg.obj);
break;
- case MSG_SWITCH_KEYBOARD_LAYOUT: {
- SomeArgs args = (SomeArgs)msg.obj;
- handleSwitchKeyboardLayout((InputDeviceIdentifier)args.arg1,
- (InputMethodSubtypeHandle)args.arg2);
+ case MSG_SWITCH_KEYBOARD_LAYOUT:
+ handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
break;
- }
case MSG_RELOAD_KEYBOARD_LAYOUTS:
reloadKeyboardLayouts();
break;
@@ -2341,25 +2222,6 @@ public class InputManagerService extends IInputManager.Stub
}
}
- private class Shell extends ShellCommand {
- @Override
- public int onCommand(String cmd) {
- return onShellCommand(this, cmd);
- }
-
- @Override
- public void onHelp() {
- final PrintWriter pw = getOutPrintWriter();
- pw.println("Input manager commands:");
- pw.println(" help");
- pw.println(" Print this help text.");
- pw.println("");
- pw.println(" setlayout IME_ID IME_SUPTYPE_HASH_CODE"
- + " DEVICE_DESCRIPTOR VENDOR_ID PRODUCT_ID KEYBOARD_DESCRIPTOR");
- pw.println(" Sets a keyboard layout for a given IME subtype and input device pair");
- }
- }
-
private final class LocalService extends InputManagerInternal {
@Override
public void setDisplayViewports(DisplayViewport defaultViewport,
diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
index c9f8b208469..196787aa5cd 100644
--- a/services/core/java/com/android/server/input/PersistentDataStore.java
+++ b/services/core/java/com/android/server/input/PersistentDataStore.java
@@ -16,7 +16,6 @@
package com.android.server.input;
-import com.android.internal.inputmethod.InputMethodSubtypeHandle;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
@@ -28,8 +27,6 @@ import org.xmlpull.v1.XmlSerializer;
import android.annotation.Nullable;
import android.view.Surface;
import android.hardware.input.TouchCalibration;
-import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.Xml;
@@ -41,13 +38,10 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -139,26 +133,9 @@ final class PersistentDataStore {
}
return state.getKeyboardLayouts();
}
- public String getKeyboardLayout(String inputDeviceDescriptor,
- InputMethodSubtypeHandle imeHandle) {
- InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
- if (state == null) {
- return null;
- }
- return state.getKeyboardLayout(imeHandle);
- }
- public boolean setKeyboardLayout(String inputDeviceDescriptor,
- InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
- InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
- if (state.setKeyboardLayout(imeHandle, keyboardLayoutDescriptor)) {
- setDirty();
- return true;
- }
- return false;
- }
-
- public boolean addKeyboardLayout(String inputDeviceDescriptor, String keyboardLayoutDescriptor) {
+ public boolean addKeyboardLayout(String inputDeviceDescriptor,
+ String keyboardLayoutDescriptor) {
InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
if (state.addKeyboardLayout(keyboardLayoutDescriptor)) {
setDirty();
@@ -177,10 +154,9 @@ final class PersistentDataStore {
return false;
}
- public boolean switchKeyboardLayout(String inputDeviceDescriptor,
- InputMethodSubtypeHandle imeHandle) {
+ public boolean switchKeyboardLayout(String inputDeviceDescriptor, int direction) {
InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
- if (state != null && state.switchKeyboardLayout(imeHandle)) {
+ if (state != null && state.switchKeyboardLayout(direction)) {
setDirty();
return true;
}
@@ -327,18 +303,6 @@ final class PersistentDataStore {
serializer.endDocument();
}
- public void dump(PrintWriter pw, String prefix) {
- pw.println(prefix + "PersistentDataStore");
- pw.println(prefix + " mLoaded=" + mLoaded);
- pw.println(prefix + " mDirty=" + mDirty);
- pw.println(prefix + " InputDeviceStates:");
- int i = 0;
- for (Map.Entry entry : mInputDevices.entrySet()) {
- pw.println(prefix + " " + i++ + ": " + entry.getKey());
- entry.getValue().dump(pw, prefix + " ");
- }
- }
-
private static final class InputDeviceState {
private static final String[] CALIBRATION_NAME = { "x_scale",
"x_ymix", "x_offset", "y_xmix", "y_scale", "y_offset" };
@@ -346,8 +310,7 @@ final class PersistentDataStore {
private TouchCalibration[] mTouchCalibration = new TouchCalibration[4];
@Nullable
private String mCurrentKeyboardLayout;
- private List mUnassociatedKeyboardLayouts = new ArrayList<>();
- private ArrayMap mKeyboardLayouts = new ArrayMap<>();
+ private ArrayList mKeyboardLayouts = new ArrayList();
public TouchCalibration getTouchCalibration(int surfaceRotation) {
try {
@@ -386,34 +349,18 @@ final class PersistentDataStore {
}
public String[] getKeyboardLayouts() {
- if (mUnassociatedKeyboardLayouts.isEmpty()) {
+ if (mKeyboardLayouts.isEmpty()) {
return (String[])ArrayUtils.emptyArray(String.class);
}
- return mUnassociatedKeyboardLayouts.toArray(
- new String[mUnassociatedKeyboardLayouts.size()]);
- }
-
- public String getKeyboardLayout(InputMethodSubtypeHandle handle) {
- return mKeyboardLayouts.get(handle);
- }
-
- public boolean setKeyboardLayout(InputMethodSubtypeHandle imeHandle,
- String keyboardLayout) {
- String existingLayout = mKeyboardLayouts.get(imeHandle);
- if (TextUtils.equals(existingLayout, keyboardLayout)) {
- return false;
- }
- mKeyboardLayouts.put(imeHandle, keyboardLayout);
- return true;
+ return mKeyboardLayouts.toArray(new String[mKeyboardLayouts.size()]);
}
public boolean addKeyboardLayout(String keyboardLayout) {
- int index = Collections.binarySearch(
- mUnassociatedKeyboardLayouts, keyboardLayout);
+ int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
if (index >= 0) {
return false;
}
- mUnassociatedKeyboardLayouts.add(-index - 1, keyboardLayout);
+ mKeyboardLayouts.add(-index - 1, keyboardLayout);
if (mCurrentKeyboardLayout == null) {
mCurrentKeyboardLayout = keyboardLayout;
}
@@ -421,11 +368,11 @@ final class PersistentDataStore {
}
public boolean removeKeyboardLayout(String keyboardLayout) {
- int index = Collections.binarySearch(mUnassociatedKeyboardLayouts, keyboardLayout);
+ int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
if (index < 0) {
return false;
}
- mUnassociatedKeyboardLayouts.remove(index);
+ mKeyboardLayouts.remove(index);
updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, index);
return true;
}
@@ -433,34 +380,41 @@ final class PersistentDataStore {
private void updateCurrentKeyboardLayoutIfRemoved(
String removedKeyboardLayout, int removedIndex) {
if (Objects.equals(mCurrentKeyboardLayout, removedKeyboardLayout)) {
- if (!mUnassociatedKeyboardLayouts.isEmpty()) {
+ if (!mKeyboardLayouts.isEmpty()) {
int index = removedIndex;
- if (index == mUnassociatedKeyboardLayouts.size()) {
+ if (index == mKeyboardLayouts.size()) {
index = 0;
}
- mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(index);
+ mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
} else {
mCurrentKeyboardLayout = null;
}
}
}
- public boolean switchKeyboardLayout(InputMethodSubtypeHandle imeHandle) {
- final String layout = mKeyboardLayouts.get(imeHandle);
- if (!TextUtils.equals(mCurrentKeyboardLayout, layout)) {
- mCurrentKeyboardLayout = layout;
- return true;
+ public boolean switchKeyboardLayout(int direction) {
+ final int size = mKeyboardLayouts.size();
+ if (size < 2) {
+ return false;
+ }
+ int index = Collections.binarySearch(mKeyboardLayouts, mCurrentKeyboardLayout);
+ assert index >= 0;
+ if (direction > 0) {
+ index = (index + 1) % size;
+ } else {
+ index = (index + size - 1) % size;
}
- return false;
+ mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
+ return true;
}
public boolean removeUninstalledKeyboardLayouts(Set availableKeyboardLayouts) {
boolean changed = false;
- for (int i = mUnassociatedKeyboardLayouts.size(); i-- > 0; ) {
- String keyboardLayout = mUnassociatedKeyboardLayouts.get(i);
+ for (int i = mKeyboardLayouts.size(); i-- > 0; ) {
+ String keyboardLayout = mKeyboardLayouts.get(i);
if (!availableKeyboardLayouts.contains(keyboardLayout)) {
Slog.i(TAG, "Removing uninstalled keyboard layout " + keyboardLayout);
- mUnassociatedKeyboardLayouts.remove(i);
+ mKeyboardLayouts.remove(i);
updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, i);
changed = true;
}
@@ -478,8 +432,13 @@ final class PersistentDataStore {
throw new XmlPullParserException(
"Missing descriptor attribute on keyboard-layout.");
}
-
String current = parser.getAttributeValue(null, "current");
+ if (mKeyboardLayouts.contains(descriptor)) {
+ throw new XmlPullParserException(
+ "Found duplicate keyboard layout.");
+ }
+
+ mKeyboardLayouts.add(descriptor);
if (current != null && current.equals("true")) {
if (mCurrentKeyboardLayout != null) {
throw new XmlPullParserException(
@@ -487,32 +446,6 @@ final class PersistentDataStore {
}
mCurrentKeyboardLayout = descriptor;
}
-
- String inputMethodId = parser.getAttributeValue(null, "input-method-id");
- String inputMethodSubtypeId =
- parser.getAttributeValue(null, "input-method-subtype-id");
- if (inputMethodId == null && inputMethodSubtypeId != null
- || inputMethodId != null && inputMethodSubtypeId == null) {
- throw new XmlPullParserException(
- "Found an incomplete input method description");
- }
-
- if (inputMethodSubtypeId != null) {
- InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
- inputMethodId, Integer.parseInt(inputMethodSubtypeId));
- if (mKeyboardLayouts.containsKey(handle)) {
- throw new XmlPullParserException(
- "Found duplicate subtype to keyboard layout mapping: "
- + handle);
- }
- mKeyboardLayouts.put(handle, descriptor);
- } else {
- if (mUnassociatedKeyboardLayouts.contains(descriptor)) {
- throw new XmlPullParserException(
- "Found duplicate unassociated keyboard layout: " + descriptor);
- }
- mUnassociatedKeyboardLayouts.add(descriptor);
- }
} else if (parser.getName().equals("calibration")) {
String format = parser.getAttributeValue(null, "format");
String rotation = parser.getAttributeValue(null, "rotation");
@@ -563,31 +496,19 @@ final class PersistentDataStore {
}
// Maintain invariant that layouts are sorted.
- Collections.sort(mUnassociatedKeyboardLayouts);
+ Collections.sort(mKeyboardLayouts);
// Maintain invariant that there is always a current keyboard layout unless
// there are none installed.
- if (mCurrentKeyboardLayout == null && !mUnassociatedKeyboardLayouts.isEmpty()) {
- mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(0);
+ if (mCurrentKeyboardLayout == null && !mKeyboardLayouts.isEmpty()) {
+ mCurrentKeyboardLayout = mKeyboardLayouts.get(0);
}
}
public void saveToXml(XmlSerializer serializer) throws IOException {
- for (String layout : mUnassociatedKeyboardLayouts) {
- serializer.startTag(null, "keyboard-layout");
- serializer.attribute(null, "descriptor", layout);
- serializer.endTag(null, "keyboard-layout");
- }
-
- final int N = mKeyboardLayouts.size();
- for (int i = 0; i < N; i++) {
- final InputMethodSubtypeHandle handle = mKeyboardLayouts.keyAt(i);
- final String layout = mKeyboardLayouts.valueAt(i);
+ for (String layout : mKeyboardLayouts) {
serializer.startTag(null, "keyboard-layout");
serializer.attribute(null, "descriptor", layout);
- serializer.attribute(null, "input-method-id", handle.getInputMethodId());
- serializer.attribute(null, "input-method-subtype-id",
- Integer.toString(handle.getSubtypeId()));
if (layout.equals(mCurrentKeyboardLayout)) {
serializer.attribute(null, "current", "true");
}
@@ -612,22 +533,6 @@ final class PersistentDataStore {
}
}
- private void dump(final PrintWriter pw, final String prefix) {
- pw.println(prefix + "CurrentKeyboardLayout=" + mCurrentKeyboardLayout);
- pw.println(prefix + "UnassociatedKeyboardLayouts=" + mUnassociatedKeyboardLayouts);
- pw.println(prefix + "TouchCalibration=" + Arrays.toString(mTouchCalibration));
- pw.println(prefix + "Subtype to Layout Mappings:");
- final int N = mKeyboardLayouts.size();
- if (N != 0) {
- for (int i = 0; i < N; i++) {
- pw.println(prefix + " " + mKeyboardLayouts.keyAt(i) + ": "
- + mKeyboardLayouts.valueAt(i));
- }
- } else {
- pw.println(prefix + " ");
- }
- }
-
private static String surfaceRotationToString(int surfaceRotation) {
switch (surfaceRotation) {
case Surface.ROTATION_0: return "0";
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8bc9830f49d..810ec11b386 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3860,6 +3860,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
hideRecentApps(true, false);
}
+ // Handle keyboard layout switching.
+ // TODO: Deprecate this behavior when we fully migrate to IME subtype-based layout rotation.
+ if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_SPACE
+ && ((metaState & KeyEvent.META_CTRL_MASK) != 0)) {
+ int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
+ mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
+ return -1;
+ }
+
// Handle input method switching.
if (down && repeatCount == 0
&& (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index d5c12f73cac..0a6f70a58dd 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -544,6 +544,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
*/
public int getCameraLensCoverState();
+ /**
+ * Switch the keyboard layout for the given device.
+ * Direction should be +1 or -1 to go to the next or previous keyboard layout.
+ */
+ public void switchKeyboardLayout(int deviceId, int direction);
+
/**
* Switch the input method, to be precise, input method subtype.
*
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2041c6fc72d..26b47dde59b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3176,6 +3176,12 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ // Called by window manager policy. Not exposed externally.
+ @Override
+ public void switchKeyboardLayout(int deviceId, int direction) {
+ mInputManager.switchKeyboardLayout(deviceId, direction);
+ }
+
// Called by window manager policy. Not exposed externally.
@Override
public void switchInputMethod(boolean forwardDirection) {
--
GitLab
From 19a4000632c22910a3f637c8c619e4cd467b3931 Mon Sep 17 00:00:00 2001
From: Yohei Yukawa
Date: Wed, 7 Mar 2018 19:15:38 -0800
Subject: [PATCH 011/488] Revert "Plumb IME subtype change from IMMS to IMS."
This reverts commit b097b8262ba22040d46d6e212a31b758b7023307 [1].
Reason for revert:
This is the part 3 of a series of reverts to unlaunch Bug 25752812,
which aimed to improve UX but did not work well.
Note that since this was just a plumbing CL, reverting this CL itself
should introduce no user-visible behavior change.
See I7a2ed6dd39dcd8207d3d94e12cd01d5d67ba4bb5 for the detailed reason
of revert.
[1]: I58e71ffce9ac9131551a00dd35e24235dadfef87
Bug: 66498367
Test: Manually done
Change-Id: I3e2b9a9faf5234e53d20953886d9d55af680087d
---
.../hardware/input/InputManagerInternal.java | 13 -------
.../server/InputMethodManagerService.java | 16 ---------
.../server/input/InputManagerService.java | 35 +------------------
3 files changed, 1 insertion(+), 63 deletions(-)
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index 4ea0f55218a..eb7ea67eb88 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -16,11 +16,8 @@
package android.hardware.input;
-import android.annotation.Nullable;
import android.hardware.display.DisplayViewport;
import android.view.InputEvent;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
import java.util.List;
@@ -45,16 +42,6 @@ public abstract class InputManagerInternal {
*/
public abstract void setInteractive(boolean interactive);
- /**
- * Notifies that InputMethodManagerService switched the current input method subtype.
- *
- * @param userId user id that indicates who is using the specified input method and subtype.
- * @param inputMethodInfo {@code null} when no input method is selected.
- * @param subtype {@code null} when {@code inputMethodInfo} does has no subtype.
- */
- public abstract void onInputMethodSubtypeChanged(int userId,
- @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype);
-
/**
* Toggles Caps Lock state for input device with specific id.
*
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 70ca1611674..5b57c14c111 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -92,7 +92,6 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
-import android.hardware.input.InputManagerInternal;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.Binder;
@@ -2490,16 +2489,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- private void notifyInputMethodSubtypeChanged(final int userId,
- @Nullable final InputMethodInfo inputMethodInfo,
- @Nullable final InputMethodSubtype subtype) {
- final InputManagerInternal inputManagerInternal =
- LocalServices.getService(InputManagerInternal.class);
- if (inputManagerInternal != null) {
- inputManagerInternal.onInputMethodSubtypeChanged(userId, inputMethodInfo, subtype);
- }
- }
-
/* package */ void setInputMethodLocked(String id, int subtypeId) {
InputMethodInfo info = mMethodMap.get(id);
if (info == null) {
@@ -2534,10 +2523,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurMethod.changeInputMethodSubtype(newSubtype);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to call changeInputMethodSubtype");
- return;
}
}
- notifyInputMethodSubtypeChanged(mSettings.getCurrentUserId(), info, newSubtype);
}
return;
}
@@ -2563,9 +2550,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
} finally {
Binder.restoreCallingIdentity(ident);
}
-
- notifyInputMethodSubtypeChanged(mSettings.getCurrentUserId(), info,
- getCurrentInputMethodSubtypeLocked());
}
@Override
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index a70909ff415..451acf4cfc9 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,7 +17,6 @@
package com.android.server.input;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.LocaleList;
import android.os.ShellCallback;
import android.util.Log;
@@ -96,8 +95,6 @@ import android.view.KeyEvent;
import android.view.PointerIcon;
import android.view.Surface;
import android.view.ViewConfiguration;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSubtype;
import android.widget.Toast;
import java.io.File;
@@ -135,7 +132,6 @@ public class InputManagerService extends IInputManager.Stub
private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
- private static final int MSG_INPUT_METHOD_SUBTYPE_CHANGED = 7;
// Pointer to native input manager service object.
private final long mPtr;
@@ -1429,15 +1425,6 @@ public class InputManagerService extends IInputManager.Stub
}
}
- // Must be called on handler.
- private void handleSwitchInputMethodSubtype(int userId,
- @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
- if (DEBUG) {
- Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
- + " ime=" + inputMethodInfo + " subtype=" + subtype);
- }
- }
-
public void switchKeyboardLayout(int deviceId, int direction) {
mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
}
@@ -2065,22 +2052,12 @@ public class InputManagerService extends IInputManager.Stub
case MSG_RELOAD_DEVICE_ALIASES:
reloadDeviceAliases();
break;
- case MSG_DELIVER_TABLET_MODE_CHANGED: {
+ case MSG_DELIVER_TABLET_MODE_CHANGED:
SomeArgs args = (SomeArgs) msg.obj;
long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
boolean inTabletMode = (boolean) args.arg1;
deliverTabletModeChanged(whenNanos, inTabletMode);
break;
- }
- case MSG_INPUT_METHOD_SUBTYPE_CHANGED: {
- final int userId = msg.arg1;
- final SomeArgs args = (SomeArgs) msg.obj;
- final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1;
- final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2;
- args.recycle();
- handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype);
- break;
- }
}
}
}
@@ -2241,16 +2218,6 @@ public class InputManagerService extends IInputManager.Stub
nativeSetInteractive(mPtr, interactive);
}
- @Override
- public void onInputMethodSubtypeChanged(int userId,
- @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
- final SomeArgs someArgs = SomeArgs.obtain();
- someArgs.arg1 = inputMethodInfo;
- someArgs.arg2 = subtype;
- mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs)
- .sendToTarget();
- }
-
@Override
public void toggleCapsLock(int deviceId) {
nativeToggleCapsLock(mPtr, deviceId);
--
GitLab
From c8ee263d6ef37dae334e83dbe18654cff50d6153 Mon Sep 17 00:00:00 2001
From: arangelov
Date: Fri, 23 Feb 2018 16:45:53 +0000
Subject: [PATCH 012/488] Move the support_transfer_ownership_metadata inside
the device admin descriptor XML.
Bug: 73750678
Test: cts-tradefed run cts-dev --module CtsDevicePolicyManagerTestCases --test com.android.cts.devicepolicy.MixedDeviceOwnerHostSideTransferTest#testTransferOwner
Test: cts-tradefed run cts-dev --module CtsDevicePolicyManagerTestCases --test com.android.cts.devicepolicy.MixedProfileOwnerHostSideTransferTest#testTransferOwner
Test: cts-tradefed run cts-dev --module CtsDevicePolicyManagerTestCases --test com.android.cts.devicepolicy.MixedDeviceOwnerHostSideTransferTest#testTransferOwnerNoMetadata
Test: cts-tradefed run cts-dev --module CtsDevicePolicyManagerTestCases --test com.android.cts.devicepolicy.MixedProfileOwnerHostSideTransferTest#testTransferOwnerNoMetadata
Test: cts-tradefed run cts-dev --module CtsAdminTestCases --test android.admin.cts.DeviceAdminInfoTest
Change-Id: I8df63af29dbcb23332e2f291b64b8782f25a751b
---
api/current.txt | 2 +-
.../android/app/admin/DeviceAdminInfo.java | 35 +++++++++++++++----
.../app/admin/DeviceAdminReceiver.java | 25 -------------
.../app/admin/DevicePolicyManager.java | 7 ++--
.../DevicePolicyManagerService.java | 3 +-
5 files changed, 34 insertions(+), 38 deletions(-)
diff --git a/api/current.txt b/api/current.txt
index 2113d5d54f5..b45c2f7ed8d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6322,6 +6322,7 @@ package android.app.admin {
method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+ method public boolean supportsTransferOwnership();
method public boolean usesPolicy(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
@@ -6386,7 +6387,6 @@ package android.app.admin {
field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
field public static final java.lang.String EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE = "android.app.extra.TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE";
- field public static final java.lang.String SUPPORT_TRANSFER_OWNERSHIP_META_DATA = "android.app.support_transfer_ownership";
}
public class DeviceAdminService extends android.app.Service {
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index ed2aaf915ef..5fbe5b39848 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -16,31 +16,31 @@
package android.app.admin;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
-import android.content.res.Resources.NotFoundException;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
import android.util.Xml;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -266,6 +266,12 @@ public final class DeviceAdminInfo implements Parcelable {
*/
int mUsesPolicies;
+ /**
+ * Whether this administrator can be a target in an ownership transfer.
+ *
+ * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle)
+ */
+ boolean mSupportsTransferOwnership;
/**
* Constructor.
@@ -347,6 +353,12 @@ public final class DeviceAdminInfo implements Parcelable {
+ getComponent() + ": " + policyName);
}
}
+ } else if (tagName.equals("support-transfer-ownership")) {
+ if (parser.next() != XmlPullParser.END_TAG) {
+ throw new XmlPullParserException(
+ "support-transfer-ownership tag must be empty.");
+ }
+ mSupportsTransferOwnership = true;
}
}
} catch (NameNotFoundException e) {
@@ -360,6 +372,7 @@ public final class DeviceAdminInfo implements Parcelable {
DeviceAdminInfo(Parcel source) {
mActivityInfo = ActivityInfo.CREATOR.createFromParcel(source);
mUsesPolicies = source.readInt();
+ mSupportsTransferOwnership = source.readBoolean();
}
/**
@@ -458,6 +471,13 @@ public final class DeviceAdminInfo implements Parcelable {
return sRevKnownPolicies.get(policyIdent).tag;
}
+ /**
+ * Return true if this administrator can be a target in an ownership transfer.
+ */
+ public boolean supportsTransferOwnership() {
+ return mSupportsTransferOwnership;
+ }
+
/** @hide */
public ArrayList getUsedPolicies() {
ArrayList res = new ArrayList();
@@ -502,6 +522,7 @@ public final class DeviceAdminInfo implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
mActivityInfo.writeToParcel(dest, flags);
dest.writeInt(mUsesPolicies);
+ dest.writeBoolean(mSupportsTransferOwnership);
}
/**
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 8c30fc40371..1c9477d08cb 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -505,31 +505,6 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
public static final String EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE =
"android.app.extra.TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE";
- /**
- * Name under which a device administration component indicates whether it supports transfer of
- * ownership. This meta-data is of type boolean. A value of true
- * allows this administrator to be used as a target administrator for a transfer. If the value
- * is false, ownership cannot be transferred to this administrator. The default
- * value is false.
- *
This metadata is used to avoid ownership transfer migration to an administrator with a
- * version which does not yet support it.
- *
- *
- * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle)
- */
- public static final String SUPPORT_TRANSFER_OWNERSHIP_META_DATA =
- "android.app.support_transfer_ownership";
-
private DevicePolicyManager mManager;
private ComponentName mWho;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d42fa996cef..6511f214f19 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9302,9 +9302,10 @@ public class DevicePolicyManager {
* after calling this method.
*
*
The incoming target administrator must have the
- * {@link DeviceAdminReceiver#SUPPORT_TRANSFER_OWNERSHIP_META_DATA} meta-data tag
- * included in its corresponding receiver component with a value of {@code true}.
- * Otherwise an {@link IllegalArgumentException} will be thrown.
+ * <support-transfer-ownership /> tag inside the
+ * <device-admin></device-admin> tags in the xml file referenced by
+ * {@link DeviceAdminReceiver#DEVICE_ADMIN_META_DATA}. Otherwise an
+ * {@link IllegalArgumentException} will be thrown.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with
* @param target which {@link DeviceAdminReceiver} we want the new administrator to be
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ab8a6c4d754..83c9f7cd6a8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -12658,8 +12658,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final DeviceAdminInfo incomingDeviceInfo = findAdmin(target, callingUserId,
/* throwForMissingPermission= */ true);
checkActiveAdminPrecondition(target, incomingDeviceInfo, policy);
- if (!incomingDeviceInfo.getActivityInfo().metaData
- .getBoolean(DeviceAdminReceiver.SUPPORT_TRANSFER_OWNERSHIP_META_DATA, false)) {
+ if (!incomingDeviceInfo.supportsTransferOwnership()) {
throw new IllegalArgumentException("Provided target does not support "
+ "ownership transfer.");
}
--
GitLab
From c7bf3e206ae16feb9202f58a63dd2adbf16be004 Mon Sep 17 00:00:00 2001
From: Alan Viverette
Date: Thu, 8 Mar 2018 15:35:11 -0500
Subject: [PATCH 013/488] Migrate multidex to androidx
Bug: 74397601
Test: make
Change-Id: Iee933e9b64e313a8880accc0dbf7f9e0c7706784
---
.../com/android/multidexlegacyandexception/TestApplication.java | 2 +-
.../tests/MultiDexAndroidJUnitRunner.java | 2 +-
.../src/com/android/multidexlegacytestapp/TestApplication.java | 2 +-
.../multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java | 2 +-
.../MultiDexLegacyTestAppWithCorruptedDex/AndroidManifest.xml | 2 +-
.../framework/multidexlegacytestservices/AbstractService.java | 2 +-
.../MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml | 2 +-
.../MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml | 2 +-
.../MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml | 2 +-
9 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/TestApplication.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/TestApplication.java
index dece9a45cfd..bcf94909cef 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/TestApplication.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/TestApplication.java
@@ -16,7 +16,7 @@
package com.android.multidexlegacyandexception;
-import android.support.multidex.MultiDexApplication;
+import androidx.multidex.MultiDexApplication;
public class TestApplication extends MultiDexApplication {
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java
index 758ac1dcb4a..92a3b0c0f7c 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java
@@ -17,7 +17,7 @@
package com.android.multidexlegacyandexception.tests;
import android.os.Bundle;
-import android.support.multidex.MultiDex;
+import androidx.multidex.MultiDex;
import android.support.test.runner.AndroidJUnitRunner;
public class MultiDexAndroidJUnitRunner extends AndroidJUnitRunner {
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/TestApplication.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/TestApplication.java
index c52ad292b6d..f89d1325961 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/TestApplication.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/TestApplication.java
@@ -16,7 +16,7 @@
package com.android.multidexlegacytestapp;
-import android.support.multidex.MultiDexApplication;
+import androidx.multidex.MultiDexApplication;
import java.lang.annotation.Annotation;
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java
index 963f90432dd..9e41a925de8 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java
@@ -1,7 +1,7 @@
package com.android.multidexlegacytestapp.test2;
import android.os.Bundle;
-import android.support.multidex.MultiDex;
+import androidx.multidex.MultiDex;
import android.support.test.runner.AndroidJUnitRunner;
public class MultiDexAndroidJUnitRunner extends AndroidJUnitRunner {
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/AndroidManifest.xml
index 7993c6f48f8..5f006fe59a6 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppWithCorruptedDex/AndroidManifest.xml
@@ -9,7 +9,7 @@
android:targetSdkVersion="18" />
Date: Thu, 8 Mar 2018 12:43:58 -0800
Subject: [PATCH 014/488] Remove kPullerCooldownMap from code
remove dead code
Bug: 74032852
Test: manual test
Change-Id: I0da74be21bab5842a89ede2a272094ba5ee33d80
---
cmds/statsd/src/external/StatsPuller.cpp | 7 ++-----
cmds/statsd/src/guardrail/StatsdStats.cpp | 12 ------------
cmds/statsd/src/guardrail/StatsdStats.h | 7 -------
3 files changed, 2 insertions(+), 24 deletions(-)
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index 9513cc521af..3b0cd349168 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -21,6 +21,7 @@
#include "guardrail/StatsdStats.h"
#include "puller_util.h"
#include "stats_log_util.h"
+#include "StatsPullerManagerImpl.h"
namespace android {
namespace os {
@@ -34,11 +35,7 @@ void StatsPuller::SetUidMap(const sp& uidMap) { mUidMap = uidMap; }
// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
StatsPuller::StatsPuller(const int tagId)
: mTagId(tagId) {
- if (StatsdStats::kPullerCooldownMap.find(tagId) == StatsdStats::kPullerCooldownMap.end()) {
- mCoolDownSec = StatsdStats::kDefaultPullerCooldown;
- } else {
- mCoolDownSec = StatsdStats::kPullerCooldownMap[tagId];
- }
+ mCoolDownSec = StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.coolDownSec;
VLOG("Puller for tag %d created. Cooldown set to %ld", mTagId, mCoolDownSec);
}
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index d626d901cdd..c6c4d135ad3 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -91,18 +91,6 @@ const int FIELD_ID_UID_MAP_BYTES_USED = 3;
const int FIELD_ID_UID_MAP_DROPPED_SNAPSHOTS = 4;
const int FIELD_ID_UID_MAP_DROPPED_CHANGES = 5;
-std::map StatsdStats::kPullerCooldownMap = {
- {android::util::KERNEL_WAKELOCK, 1},
- {android::util::WIFI_BYTES_TRANSFER, 1},
- {android::util::MOBILE_BYTES_TRANSFER, 1},
- {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG, 1},
- {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG, 1},
- {android::util::SUBSYSTEM_SLEEP_STATE, 1},
- {android::util::CPU_TIME_PER_FREQ, 1},
- {android::util::CPU_TIME_PER_UID, 1},
- {android::util::CPU_TIME_PER_UID_FREQ, 1},
-};
-
// TODO: add stats for pulled atoms.
StatsdStats::StatsdStats() {
mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index c3f40132445..d05c91b8d18 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -111,13 +111,6 @@ public:
/* Min period between two checks of byte size per config key in nanoseconds. */
static const unsigned long long kMinByteSizeCheckPeriodNs = 10 * NS_PER_SEC;
- // Default minimum interval between pulls for an atom. Pullers can return cached values if
- // another pull request happens within this interval.
- static std::map kPullerCooldownMap;
-
- // Default cooldown time for a puller
- static const long kDefaultPullerCooldown = 1;
-
// Maximum age (30 days) that files on disk can exist in seconds.
static const int kMaxAgeSecond = 60 * 60 * 24 * 30;
--
GitLab
From 4afdae952eeb2bafeae6b8b00cb2626098e79a66 Mon Sep 17 00:00:00 2001
From: Mohamed Abdalkader
Date: Thu, 8 Mar 2018 12:13:17 -0800
Subject: [PATCH 015/488] Unhide ImsCallProfileConstructor.
- Unhide ImsCallProfileConstructor.
- instead of unhiding mMediaProfile added a setter simillar to other
fields.
- Unhide ImsMediaProfile constructor to be able to use it in
ImsCallProfileConstructor.
Test: manual
Bug:74391594
Change-Id: I591e357040d254c3f7225748dc53b66aa820f9c4
---
api/system-current.txt | 5 ++
.../android/telephony/ims/ImsCallProfile.java | 64 ++++++++++++++++++-
.../telephony/ims/ImsStreamMediaProfile.java | 56 ++++++++++++++++
3 files changed, 123 insertions(+), 2 deletions(-)
diff --git a/api/system-current.txt b/api/system-current.txt
index 4fc2d21c138..b8a63bdf007 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5495,6 +5495,9 @@ package android.telephony.ims {
}
public final class ImsCallProfile implements android.os.Parcelable {
+ ctor public ImsCallProfile();
+ ctor public ImsCallProfile(int, int);
+ ctor public ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile);
method public int describeContents();
method public java.lang.String getCallExtra(java.lang.String);
method public java.lang.String getCallExtra(java.lang.String, java.lang.String);
@@ -5518,6 +5521,7 @@ package android.telephony.ims {
method public void setCallExtraInt(java.lang.String, int);
method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
method public void updateCallType(android.telephony.ims.ImsCallProfile);
+ method public void updateMediaProfile(android.telephony.ims.ImsCallProfile);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CALL_RESTRICT_CAUSE_DISABLED = 2; // 0x2
field public static final int CALL_RESTRICT_CAUSE_HD = 3; // 0x3
@@ -5855,6 +5859,7 @@ package android.telephony.ims {
}
public final class ImsStreamMediaProfile implements android.os.Parcelable {
+ ctor public ImsStreamMediaProfile(int, int, int, int, int);
method public void copyFrom(android.telephony.ims.ImsStreamMediaProfile);
method public int describeContents();
method public int getAudioDirection();
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 27e5f943982..350dfe3a8d0 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -296,7 +296,10 @@ public final class ImsCallProfile implements Parcelable {
readFromParcel(in);
}
- /** @hide */
+ /**
+ * Default Constructor that initializes the call profile with service type
+ * {@link #SERVICE_TYPE_NORMAL} and call type {@link #CALL_TYPE_VIDEO_N_VOICE}
+ */
public ImsCallProfile() {
mServiceType = SERVICE_TYPE_NORMAL;
mCallType = CALL_TYPE_VOICE_N_VIDEO;
@@ -304,7 +307,25 @@ public final class ImsCallProfile implements Parcelable {
mMediaProfile = new ImsStreamMediaProfile();
}
- /** @hide */
+ /**
+ * Constructor.
+ *
+ * @param serviceType the service type for the call. Can be one of the following:
+ * {@link #SERVICE_TYPE_NONE},
+ * {@link #SERVICE_TYPE_NORMAL},
+ * {@link #SERVICE_TYPE_EMERGENCY}
+ * @param callType the call type. Can be one of the following:
+ * {@link #CALL_TYPE_VOICE_N_VIDEO},
+ * {@link #CALL_TYPE_VOICE},
+ * {@link #CALL_TYPE_VIDEO_N_VOICE},
+ * {@link #CALL_TYPE_VT},
+ * {@link #CALL_TYPE_VT_TX},
+ * {@link #CALL_TYPE_VT_RX},
+ * {@link #CALL_TYPE_VT_NODIR},
+ * {@link #CALL_TYPE_VS},
+ * {@link #CALL_TYPE_VS_TX},
+ * {@link #CALL_TYPE_VS_RX}
+ */
public ImsCallProfile(int serviceType, int callType) {
mServiceType = serviceType;
mCallType = callType;
@@ -312,6 +333,35 @@ public final class ImsCallProfile implements Parcelable {
mMediaProfile = new ImsStreamMediaProfile();
}
+ /**
+ * Constructor.
+ *
+ * @param serviceType the service type for the call. Can be one of the following:
+ * {@link #SERVICE_TYPE_NONE},
+ * {@link #SERVICE_TYPE_NORMAL},
+ * {@link #SERVICE_TYPE_EMERGENCY}
+ * @param callType the call type. Can be one of the following:
+ * {@link #CALL_TYPE_VOICE_N_VIDEO},
+ * {@link #CALL_TYPE_VOICE},
+ * {@link #CALL_TYPE_VIDEO_N_VOICE},
+ * {@link #CALL_TYPE_VT},
+ * {@link #CALL_TYPE_VT_TX},
+ * {@link #CALL_TYPE_VT_RX},
+ * {@link #CALL_TYPE_VT_NODIR},
+ * {@link #CALL_TYPE_VS},
+ * {@link #CALL_TYPE_VS_TX},
+ * {@link #CALL_TYPE_VS_RX}
+ * @param callExtras A bundle with the call extras.
+ * @param mediaProfile The IMS stream media profile.
+ */
+ public ImsCallProfile(int serviceType, int callType, Bundle callExtras,
+ ImsStreamMediaProfile mediaProfile) {
+ mServiceType = serviceType;
+ mCallType = callType;
+ mCallExtras = callExtras;
+ mMediaProfile = mediaProfile;
+ }
+
public String getCallExtra(String name) {
return getCallExtra(name, "");
}
@@ -375,6 +425,16 @@ public final class ImsCallProfile implements Parcelable {
mCallExtras = (Bundle) profile.mCallExtras.clone();
}
+ /**
+ * Updates the media profile for the call.
+ *
+ * @param profile Call profile with new media profile.
+ */
+ public void updateMediaProfile(ImsCallProfile profile) {
+ mMediaProfile = profile.mMediaProfile;
+ }
+
+
@Override
public String toString() {
return "{ serviceType=" + mServiceType +
diff --git a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
index 243352bdd18..137106a011b 100644
--- a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
@@ -99,6 +99,62 @@ public final class ImsStreamMediaProfile implements Parcelable {
readFromParcel(in);
}
+ /**
+ * Constructor.
+ *
+ * @param audioQuality The audio quality. Can be one of the following:
+ * {@link #AUDIO_QUALITY_AMR},
+ * {@link #AUDIO_QUALITY_AMR_WB},
+ * {@link #AUDIO_QUALITY_QCELP13K},
+ * {@link #AUDIO_QUALITY_EVRC},
+ * {@link #AUDIO_QUALITY_EVRC_B},
+ * {@link #AUDIO_QUALITY_EVRC_WB},
+ * {@link #AUDIO_QUALITY_EVRC_NW},
+ * {@link #AUDIO_QUALITY_GSM_EFR},
+ * {@link #AUDIO_QUALITY_GSM_FR},
+ * {@link #AUDIO_QUALITY_GSM_HR},
+ * {@link #AUDIO_QUALITY_G711U},
+ * {@link #AUDIO_QUALITY_G723},
+ * {@link #AUDIO_QUALITY_G711A},
+ * {@link #AUDIO_QUALITY_G722},
+ * {@link #AUDIO_QUALITY_G711AB},
+ * {@link #AUDIO_QUALITY_G729},
+ * {@link #AUDIO_QUALITY_EVS_NB},
+ * {@link #AUDIO_QUALITY_EVS_WB},
+ * {@link #AUDIO_QUALITY_EVS_SWB},
+ * {@link #AUDIO_QUALITY_EVS_FB},
+ * @param audioDirection The audio direction. Can be one of the following:
+ * {@link #DIRECTION_INVALID},
+ * {@link #DIRECTION_INACTIVE},
+ * {@link #DIRECTION_RECEIVE},
+ * {@link #DIRECTION_SEND},
+ * {@link #DIRECTION_SEND_RECEIVE},
+ * @param videoQuality The video quality. Can be one of the following:
+ * {@link #VIDEO_QUALITY_NONE},
+ * {@link #VIDEO_QUALITY_QCIF},
+ * {@link #VIDEO_QUALITY_QVGA_LANDSCAPE},
+ * {@link #VIDEO_QUALITY_QVGA_PORTRAIT},
+ * {@link #VIDEO_QUALITY_VGA_LANDSCAPE},
+ * {@link #VIDEO_QUALITY_VGA_PORTRAIT},
+ * @param videoDirection The video direction. Can be one of the following:
+ * {@link #DIRECTION_INVALID},
+ * {@link #DIRECTION_INACTIVE},
+ * {@link #DIRECTION_RECEIVE},
+ * {@link #DIRECTION_SEND},
+ * {@link #DIRECTION_SEND_RECEIVE},
+ * @param rttMode The rtt mode. Can be one of the following:
+ * {@link #RTT_MODE_DISABLED},
+ * {@link #RTT_MODE_FULL}
+ */
+ public ImsStreamMediaProfile(int audioQuality, int audioDirection,
+ int videoQuality, int videoDirection, int rttMode) {
+ mAudioQuality = audioQuality;
+ mAudioDirection = audioDirection;
+ mVideoQuality = videoQuality;
+ mVideoDirection = videoDirection;
+ mRttMode = rttMode;
+ }
+
/** @hide */
public ImsStreamMediaProfile() {
mAudioQuality = AUDIO_QUALITY_NONE;
--
GitLab
From 65870a8188daaa0bbb9465cbf7d96fb27e7826bf Mon Sep 17 00:00:00 2001
From: Alison Cichowlas
Date: Thu, 8 Mar 2018 16:48:06 -0500
Subject: [PATCH 016/488] Stop closing other dialogs when opening
GlobalActions.
Bug: 73775739
Test: Manual
Change-Id: I0947397d70d7c1c2880d03e45cd2b76607876331
---
.../core/java/com/android/server/policy/PhoneWindowManager.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index a0e4f4f2856..1ad220885a2 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1755,7 +1755,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
void showGlobalActionsInternal() {
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
if (mGlobalActions == null) {
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
}
--
GitLab
From b19425e01113f3341c48f5283affd386658281b0 Mon Sep 17 00:00:00 2001
From: Yao Chen
Date: Thu, 8 Mar 2018 14:38:12 -0800
Subject: [PATCH 017/488] Remove unused shared lib from statsd
Test: build statsd, and statsd_test
Bug: 72129300
Change-Id: I0ebff977dabe796799a0d41c64adb2c2f2e9035e
---
cmds/statsd/Android.mk | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 7f0a26c1714..3b679fc5cef 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -82,10 +82,8 @@ statsd_common_static_libraries := \
statsd_common_shared_libraries := \
libbase \
libbinder \
- libcutils \
libincident \
liblog \
- libselinux \
libutils \
libservices \
libprotoutil \
@@ -308,4 +306,4 @@ statsd_common_static_libraries:=
statsd_common_shared_libraries:=
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
--
GitLab
From c8d483e488b8fb75e997a4a48c632e20cae0f4b7 Mon Sep 17 00:00:00 2001
From: fionaxu
Date: Wed, 7 Mar 2018 21:52:05 -0800
Subject: [PATCH 018/488] Carrier id api rename
Rename getAndroidCarrierIdForSubscription to getSimCarrierId.
Drop prefix "Android" as Android is implicit everywhere.
Rename carrierName to CarrierIdName to imply correlation between
these two APIs. This also helps to differentiate from another API
getSimOperatorName.
Bug: 71584605
Test: build
Change-Id: Iba4b1c21522741b8c11836a4c39004064736b4c6
---
api/current.txt | 4 ++--
.../java/android/provider/Telephony.java | 6 +++---
.../android/telephony/TelephonyManager.java | 21 +++++++++----------
.../internal/telephony/ITelephony.aidl | 4 ++--
4 files changed, 17 insertions(+), 18 deletions(-)
diff --git a/api/current.txt b/api/current.txt
index 2113d5d54f5..c85981c7c14 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -43066,8 +43066,6 @@ package android.telephony {
method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
method public android.telephony.TelephonyManager createForSubscriptionId(int);
method public java.util.List getAllCellInfo();
- method public int getAndroidCarrierIdForSubscription();
- method public java.lang.CharSequence getAndroidCarrierNameForSubscription();
method public int getCallState();
method public android.os.PersistableBundle getCarrierConfig();
method public deprecated android.telephony.CellLocation getCellLocation();
@@ -43098,6 +43096,8 @@ package android.telephony {
method public int getPhoneType();
method public android.telephony.ServiceState getServiceState();
method public android.telephony.SignalStrength getSignalStrength();
+ method public int getSimCarrierId();
+ method public java.lang.CharSequence getSimCarrierIdName();
method public java.lang.String getSimCountryIso();
method public java.lang.String getSimOperator();
method public java.lang.String getSimOperatorName();
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index fb52ff704a1..4f78c4cc78a 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3380,7 +3380,7 @@ public final class Telephony {
* on the given subscriptionId
*
* Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
- * carrier identity {@link TelephonyManager#getAndroidCarrierIdForSubscription()}
+ * carrier identity {@link TelephonyManager#getSimCarrierId()}
* while your app is running. You can also use a {@link JobService} to ensure your app
* is notified of changes to the {@link Uri} even when it is not running.
* Note, however, that using a {@link JobService} does not guarantee timely delivery of
@@ -3396,14 +3396,14 @@ public final class Telephony {
/**
* A user facing carrier name.
- * @see TelephonyManager#getAndroidCarrierNameForSubscription()
+ * @see TelephonyManager#getSimCarrierIdName()
*
Type: TEXT
*/
public static final String CARRIER_NAME = "carrier_name";
/**
* A unique carrier id
- * @see TelephonyManager#getAndroidCarrierIdForSubscription()
+ * @see TelephonyManager#getSimCarrierId()
*
Type: INTEGER
*/
public static final String CARRIER_ID = "carrier_id";
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index af3a0bb781c..b7cf0bbe687 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -52,7 +52,6 @@ import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsMmTelFeature;
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
-import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.Log;
@@ -1080,7 +1079,7 @@ public class TelephonyManager {
/**
* An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates
- * the updated carrier id {@link TelephonyManager#getAndroidCarrierIdForSubscription()} of
+ * the updated carrier id {@link TelephonyManager#getSimCarrierId()} of
* the current subscription.
*
Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or
* the carrier cannot be identified.
@@ -1090,7 +1089,7 @@ public class TelephonyManager {
/**
* An string extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which
* indicates the updated carrier name of the current subscription.
- * {@see TelephonyManager#getSubscriptionCarrierName()}
+ * {@see TelephonyManager#getSimCarrierIdName()}
*
Carrier name is a user-facing name of the carrier id {@link #EXTRA_CARRIER_ID},
* usually the brand name of the subsidiary (e.g. T-Mobile).
*/
@@ -7192,8 +7191,8 @@ public class TelephonyManager {
/**
* Returns carrier id of the current subscription.
*
To recognize a carrier (including MVNO) as a first-class identity, Android assigns each
- * carrier with a canonical integer a.k.a. android carrier id. The Android carrier ID is an
- * Android platform-wide identifier for a carrier. AOSP maintains carrier ID assignments in
+ * carrier with a canonical integer a.k.a. carrier id. The carrier ID is an Android
+ * platform-wide identifier for a carrier. AOSP maintains carrier ID assignments in
* here
*
*
Apps which have carrier-specific configurations or business logic can use the carrier id
@@ -7202,7 +7201,7 @@ public class TelephonyManager {
* @return Carrier id of the current subscription. Return {@link #UNKNOWN_CARRIER_ID} if the
* subscription is unavailable or the carrier cannot be identified.
*/
- public int getAndroidCarrierIdForSubscription() {
+ public int getSimCarrierId() {
try {
ITelephony service = getITelephony();
if (service != null) {
@@ -7216,18 +7215,18 @@ public class TelephonyManager {
}
/**
- * Returns carrier name of the current subscription.
- *
Carrier name is a user-facing name of carrier id
- * {@link #getAndroidCarrierIdForSubscription()}, usually the brand name of the subsidiary
+ * Returns carrier id name of the current subscription.
+ *
Carrier id name is a user-facing name of carrier id
+ * {@link #getSimCarrierId()}, usually the brand name of the subsidiary
* (e.g. T-Mobile). Each carrier could configure multiple {@link #getSimOperatorName() SPN} but
* should have a single carrier name. Carrier name is not a canonical identity,
- * use {@link #getAndroidCarrierIdForSubscription()} instead.
+ * use {@link #getSimCarrierId()} instead.
*
The returned carrier name is unlocalized.
*
* @return Carrier name of the current subscription. Return {@code null} if the subscription is
* unavailable or the carrier cannot be identified.
*/
- public CharSequence getAndroidCarrierNameForSubscription() {
+ public CharSequence getSimCarrierIdName() {
try {
ITelephony service = getITelephony();
if (service != null) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a941a5671f1..4002d3c94db 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1358,10 +1358,10 @@ interface ITelephony {
/**
* Returns carrier name of the given subscription.
- *
Carrier name is a user-facing name of carrier id {@link #getSubscriptionCarrierId(int)},
+ *
Carrier name is a user-facing name of carrier id {@link #getSimCarrierId(int)},
* usually the brand name of the subsidiary (e.g. T-Mobile). Each carrier could configure
* multiple {@link #getSimOperatorName() SPN} but should have a single carrier name.
- * Carrier name is not canonical identity, use {@link #getSubscriptionCarrierId(int)} instead.
+ * Carrier name is not canonical identity, use {@link #getSimCarrierId(int)} instead.
*
Returned carrier name is unlocalized.
*
* @return Carrier name of given subscription id. return {@code null} if subscription is
--
GitLab
From b7913e1f8a5d0607b0897915afb6e73a263282ab Mon Sep 17 00:00:00 2001
From: Pirama Arumuga Nainar
Date: Fri, 9 Mar 2018 00:03:57 +0000
Subject: [PATCH 019/488] Revert "Disable LTO temporarily for hwui"
Bug: http://b/62839002
Bug: http://b/74395273
Turn LTO back on for hwui. The reason for the build breaks were stale profile files in ccache. We'll hold off on updating profile files until this can be fixed. LTO can be turned back on in the mean time.
This reverts commit 7184e28b3ae349ae2e64693ac6d4c72a33ec3a61.
Change-Id: I051c39a44be6a85682393e7d6e78f49b30bb85e1
---
libs/hwui/Android.bp | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 813eae74a05..35790b6558c 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -6,10 +6,7 @@ cc_defaults {
//"hwui_bugreport_font_cache_usage",
//"hwui_compile_for_perf",
"hwui_pgo",
- // Disable LTO temporarily. LTO does not seem to interact well with
- // PGO profile-file updates and incremental builds in the build
- // servers.
- // "hwui_lto",
+ "hwui_lto",
],
cpp_std: "c++17",
--
GitLab
From 27e1f26e0149d2e38373d0d3d59bbb30f4f291a5 Mon Sep 17 00:00:00 2001
From: Kevin Chyn
Date: Thu, 8 Mar 2018 16:38:32 -0800
Subject: [PATCH 020/488] Polish FingerprintDialog
Bug: 73818869
Test: dialog matches spec
Change-Id: Ibba456e656559ffbebf1bcae79480ce91772572f
---
.../res/drawable/fingerprint_dialog_bg.xml | 26 +++++++++++++++
.../res/layout/fingerprint_dialog.xml | 19 +++++------
packages/SystemUI/res/values/colors.xml | 10 +++---
packages/SystemUI/res/values/dimens.xml | 3 +-
packages/SystemUI/res/values/integers.xml | 19 +++++++++++
.../fingerprint/FingerprintDialogImpl.java | 2 +-
.../fingerprint/FingerprintDialogView.java | 32 +++++++++++++++++--
7 files changed, 93 insertions(+), 18 deletions(-)
create mode 100644 packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
create mode 100644 packages/SystemUI/res/values/integers.xml
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
new file mode 100644
index 00000000000..221f1701187
--- /dev/null
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/fingerprint_dialog.xml b/packages/SystemUI/res/layout/fingerprint_dialog.xml
index f02c0ba35e7..1b47489418b 100644
--- a/packages/SystemUI/res/layout/fingerprint_dialog.xml
+++ b/packages/SystemUI/res/layout/fingerprint_dialog.xml
@@ -35,7 +35,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:elevation="2dp"
- android:background="@color/fingerprint_dialog_bg_color">
+ android:background="@drawable/fingerprint_dialog_bg">
+ android:textColor="@color/fingerprint_dialog_text_dark_color"/>
@@ -84,7 +85,7 @@
android:layout_width="@dimen/fingerprint_dialog_fp_icon_size"
android:layout_height="@dimen/fingerprint_dialog_fp_icon_size"
android:layout_gravity="center_horizontal"
- android:layout_marginTop="32dp"
+ android:layout_marginTop="48dp"
android:scaleType="fitXY"
android:contentDescription="@string/accessibility_fingerprint_dialog_fingerprint_icon" />
@@ -106,7 +107,7 @@
#fff2f2f2
- #f4ffffff
- #ff212121
- #ff757575
+ #ffffffff
+ #dd000000
+ #89000000#80000000
- #ffff5722
- #ff009688
+ #ffd93025
+ #ff008577#ccffffff
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7b1a9e193b0..702b4e143a8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -906,8 +906,9 @@
6sp
- 60dp
+ 64dp350dp
+ 2dp0dp
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
new file mode 100644
index 00000000000..8f23283478b
--- /dev/null
+++ b/packages/SystemUI/res/values/integers.xml
@@ -0,0 +1,19 @@
+
+
+
+ 8388611
+
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
index 1d43b1d7d55..4b15fbcd2e8 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
@@ -180,8 +180,8 @@ public class FingerprintDialogImpl extends SystemUI implements CommandQueue.Call
}
}
mReceiver = null;
- mWindowManager.removeView(mDialogView);
mDialogShowing = false;
+ mDialogView.startDismiss();
}
private void handleButtonNegative() {
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
index e828b2c097e..37e193654f4 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
@@ -61,7 +61,7 @@ public class FingerprintDialogView extends LinearLayout {
private final IBinder mWindowToken = new Binder();
private final Interpolator mLinearOutSlowIn;
- private final Interpolator mFastOutLinearIn;
+ private final WindowManager mWindowManager;
private final float mAnimationTranslationOffset;
private final int mErrorTextColor;
private final int mTextColor;
@@ -78,7 +78,7 @@ public class FingerprintDialogView extends LinearLayout {
super(context);
mHandler = handler;
mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
- mFastOutLinearIn = Interpolators.FAST_OUT_LINEAR_IN;
+ mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mAnimationTranslationOffset = getResources()
.getDimension(R.dimen.fingerprint_dialog_animation_translation_offset);
mErrorTextColor = Color.parseColor(
@@ -189,6 +189,34 @@ public class FingerprintDialogView extends LinearLayout {
});
}
+ public void startDismiss() {
+ final Runnable endActionRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mWindowManager.removeView(FingerprintDialogView.this);
+ }
+ };
+
+ postOnAnimation(new Runnable() {
+ @Override
+ public void run() {
+ mLayout.animate()
+ .alpha(0f)
+ .setDuration(ANIMATION_DURATION)
+ .setInterpolator(mLinearOutSlowIn)
+ .withLayer()
+ .start();
+ mDialog.animate()
+ .translationY(mAnimationTranslationOffset)
+ .setDuration(ANIMATION_DURATION)
+ .setInterpolator(mLinearOutSlowIn)
+ .withLayer()
+ .withEndAction(endActionRunnable)
+ .start();
+ }
+ });
+ }
+
public void setBundle(Bundle bundle) {
mBundle = bundle;
}
--
GitLab
From d4488d7621fbb9c490d3acb353c6e624156e83a6 Mon Sep 17 00:00:00 2001
From: Erik Kline
Date: Fri, 9 Mar 2018 15:39:43 +0900
Subject: [PATCH 021/488] Switch to BaseNetdEventCallback instead of interface
This makes adding more callback methods friction-free.
Test: as follows
Bug: 71828272
Change-Id: Iab88eccc0aa9583d493a1aa86ed0984475b929d5
---
.../android/server/net/watchlist/NetworkWatchlistService.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
index e5fc6e544f6..6907c58f13b 100644
--- a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
+++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
@@ -39,6 +39,7 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.net.INetworkWatchlistManager;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.net.BaseNetdEventCallback;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -139,7 +140,7 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
}
- private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() {
+ private final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() {
@Override
public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
long timestamp, int uid) {
--
GitLab
From f88d25e1b75d2819515e305c5b91235735f7b4d2 Mon Sep 17 00:00:00 2001
From: Jason Monk
Date: Tue, 6 Mar 2018 20:13:24 -0500
Subject: [PATCH 022/488] Add API to get currently pinned slices
Test: uiservicestests
Change-Id: I02662d08d34cf412353cece7bec1838823a14bf0
Fixes: 73123411
---
api/current.txt | 1 +
.../java/android/app/slice/ISliceManager.aidl | 1 +
core/java/android/app/slice/SliceManager.java | 12 ++++++++++
.../server/slice/PinnedSliceState.java | 12 ++++++----
.../server/slice/SliceManagerService.java | 24 +++++++++++++++----
.../server/slice/PinnedSliceStateTest.java | 11 ++-------
.../server/slice/SliceManagerServiceTest.java | 6 ++---
7 files changed, 45 insertions(+), 22 deletions(-)
diff --git a/api/current.txt b/api/current.txt
index 7e30e857eec..be6d8322fb5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7265,6 +7265,7 @@ package android.app.slice {
public class SliceManager {
method public android.app.slice.Slice bindSlice(android.net.Uri, java.util.List);
method public android.app.slice.Slice bindSlice(android.content.Intent, java.util.List);
+ method public java.util.List getPinnedSlices();
method public java.util.List getPinnedSpecs(android.net.Uri);
method public java.util.Collection getSliceDescendants(android.net.Uri);
method public android.net.Uri mapIntentToUri(android.content.Intent);
diff --git a/core/java/android/app/slice/ISliceManager.aidl b/core/java/android/app/slice/ISliceManager.aidl
index 20ec75a36ad..74e3c3ee4c8 100644
--- a/core/java/android/app/slice/ISliceManager.aidl
+++ b/core/java/android/app/slice/ISliceManager.aidl
@@ -27,6 +27,7 @@ interface ISliceManager {
SliceSpec[] getPinnedSpecs(in Uri uri, String pkg);
int checkSlicePermission(in Uri uri, String pkg, int pid, int uid);
void grantPermissionFromUser(in Uri uri, String pkg, String callingPkg, boolean allSlices);
+ Uri[] getPinnedSlices(String pkg);
byte[] getBackupPayload(int user);
void applyRestore(in byte[] payload, int user);
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index 9f9ce8d3f38..8c1976697fe 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -169,6 +169,18 @@ public class SliceManager {
}
}
+ /**
+ * Get the list of currently pinned slices for this app.
+ * @see SliceProvider#onSlicePinned
+ */
+ public @NonNull List getPinnedSlices() {
+ try {
+ return Arrays.asList(mService.getPinnedSlices(mContext.getPackageName()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Obtains a list of slices that are descendants of the specified Uri.
*
diff --git a/services/core/java/com/android/server/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java
index f9a4ea211f0..4e7fb969f39 100644
--- a/services/core/java/com/android/server/slice/PinnedSliceState.java
+++ b/services/core/java/com/android/server/slice/PinnedSliceState.java
@@ -14,9 +14,6 @@
package com.android.server.slice;
-import static android.app.slice.SliceManager.PERMISSION_GRANTED;
-
-import android.app.slice.Slice;
import android.app.slice.SliceProvider;
import android.app.slice.SliceSpec;
import android.content.ContentProviderClient;
@@ -33,7 +30,6 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -54,18 +50,24 @@ public class PinnedSliceState {
private final ArraySet mPinnedPkgs = new ArraySet<>();
@GuardedBy("mLock")
private final ArrayMap mListeners = new ArrayMap<>();
+ private final String mPkg;
@GuardedBy("mLock")
private SliceSpec[] mSupportedSpecs = null;
private final DeathRecipient mDeathRecipient = this::handleRecheckListeners;
private boolean mSlicePinned;
- public PinnedSliceState(SliceManagerService service, Uri uri) {
+ public PinnedSliceState(SliceManagerService service, Uri uri, String pkg) {
mService = service;
mUri = uri;
+ mPkg = pkg;
mLock = mService.getLock();
}
+ public String getPkg() {
+ return mPkg;
+ }
+
public SliceSpec[] getSpecs() {
return mSupportedSpecs;
}
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index 51e4709aa7c..a7dfd35acf1 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -148,12 +148,26 @@ public class SliceManagerService extends ISliceManager.Stub {
}
/// ----- ISliceManager stuff -----
+ @Override
+ public Uri[] getPinnedSlices(String pkg) {
+ verifyCaller(pkg);
+ ArrayList ret = new ArrayList<>();
+ synchronized (mLock) {
+ for (PinnedSliceState state : mPinnedSlicesByUri.values()) {
+ if (Objects.equals(pkg, state.getPkg())) {
+ ret.add(state.getUri());
+ }
+ }
+ }
+ return ret.toArray(new Uri[ret.size()]);
+ }
+
@Override
public void pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token) throws RemoteException {
verifyCaller(pkg);
enforceAccess(pkg, uri);
uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
- getOrCreatePinnedSlice(uri).pin(pkg, specs, token);
+ getOrCreatePinnedSlice(uri, pkg).pin(pkg, specs, token);
}
@Override
@@ -302,11 +316,11 @@ public class SliceManagerService extends ISliceManager.Stub {
}
}
- private PinnedSliceState getOrCreatePinnedSlice(Uri uri) {
+ private PinnedSliceState getOrCreatePinnedSlice(Uri uri, String pkg) {
synchronized (mLock) {
PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
if (manager == null) {
- manager = createPinnedSlice(uri);
+ manager = createPinnedSlice(uri, pkg);
mPinnedSlicesByUri.put(uri, manager);
}
return manager;
@@ -314,8 +328,8 @@ public class SliceManagerService extends ISliceManager.Stub {
}
@VisibleForTesting
- protected PinnedSliceState createPinnedSlice(Uri uri) {
- return new PinnedSliceState(this, uri);
+ protected PinnedSliceState createPinnedSlice(Uri uri, String pkg) {
+ return new PinnedSliceState(this, uri, pkg);
}
public Object getLock() {
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
index 1052e8f377a..3c4e333b6be 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -1,7 +1,5 @@
package com.android.server.slice;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -12,23 +10,18 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.slice.ISliceListener;
-import android.app.slice.Slice;
import android.app.slice.SliceProvider;
import android.app.slice.SliceSpec;
import android.content.ContentProvider;
-import android.content.Context;
import android.content.IContentProvider;
import android.net.Uri;
import android.os.Binder;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
@@ -83,7 +76,7 @@ public class PinnedSliceStateTest extends UiServiceTestCase {
mIContentProvider = mock(IContentProvider.class);
when(mContentProvider.getIContentProvider()).thenReturn(mIContentProvider);
mContext.getContentResolver().addProvider(AUTH, mContentProvider);
- mPinnedSliceManager = new PinnedSliceState(mSliceService, TEST_URI);
+ mPinnedSliceManager = new PinnedSliceState(mSliceService, TEST_URI, "pkg");
}
@Test
@@ -164,4 +157,4 @@ public class PinnedSliceStateTest extends UiServiceTestCase {
verify(mSliceService).removePinnedSlice(eq(TEST_URI));
assertFalse(mPinnedSliceManager.hasPinOrListener());
}
-}
\ No newline at end of file
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
index 6fc30095914..4f446a9afb9 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
@@ -18,6 +18,7 @@ import static android.content.ContentProvider.maybeAddUserId;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -28,7 +29,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
-import android.app.slice.ISliceListener;
import android.app.slice.SliceSpec;
import android.content.pm.PackageManagerInternal;
import android.net.Uri;
@@ -71,7 +71,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
mService = spy(new SliceManagerService(mContext, TestableLooper.get(this).getLooper()));
mCreatedSliceState = mock(PinnedSliceState.class);
- doReturn(mCreatedSliceState).when(mService).createPinnedSlice(eq(TEST_URI));
+ doReturn(mCreatedSliceState).when(mService).createPinnedSlice(eq(TEST_URI), anyString());
}
@After
@@ -85,7 +85,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
- verify(mService, times(1)).createPinnedSlice(eq(TEST_URI));
+ verify(mService, times(1)).createPinnedSlice(eq(TEST_URI), eq("pkg"));
}
@Test
--
GitLab
From 27e4dfbc2c2237d4526405b2f8aa739a9a3d1bbf Mon Sep 17 00:00:00 2001
From: Mihai Popa
Date: Wed, 7 Mar 2018 14:52:05 +0000
Subject: [PATCH 023/488] [Magnifier-32] Do not magnify outside selection
Currently, for selection, if we move one handle towards the other, the
moving handle will stop when the selection becomes 1 character long.
However, the magnifier would continue to follow the finger after this,
no longer being helpful for the selection.
This CL fixes this, by replicating what happens when the magnifier
reaches the end of the line also for the case when it reaches the other
handle.
Bug: 72314536
Test: manual testing (both English and Arabic)
Test: atest FrameworksCoreTests:android.widget.TextViewActivityTest
Test: atest CtsWidgetTestCases:android.widget.cts.TextViewTest
Change-Id: I5bde622421c7fb8ecce0ea00f0d8d2af7aa72cf4
(cherry picked from commit 2d6b40b82151aec9ff13478cd5fb58f4ab3fcb7a)
Merged-In: I5bde622421c7fb8ecce0ea00f0d8d2af7aa72cf4
---
core/java/android/widget/Editor.java | 45 +++++++++++++++++++++-------
1 file changed, 34 insertions(+), 11 deletions(-)
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 27dd39b3224..b1410f17c0e 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4660,16 +4660,23 @@ public class Editor {
final int trigger = getMagnifierHandleTrigger();
final int offset;
+ final int otherHandleOffset;
switch (trigger) {
- case MagnifierHandleTrigger.INSERTION: // Fall through.
+ case MagnifierHandleTrigger.INSERTION:
+ offset = mTextView.getSelectionStart();
+ otherHandleOffset = -1;
+ break;
case MagnifierHandleTrigger.SELECTION_START:
offset = mTextView.getSelectionStart();
+ otherHandleOffset = mTextView.getSelectionEnd();
break;
case MagnifierHandleTrigger.SELECTION_END:
offset = mTextView.getSelectionEnd();
+ otherHandleOffset = mTextView.getSelectionStart();
break;
default:
offset = -1;
+ otherHandleOffset = -1;
break;
}
@@ -4679,22 +4686,38 @@ public class Editor {
final Layout layout = mTextView.getLayout();
final int lineNumber = layout.getLineForOffset(offset);
-
- // Horizontally move the magnifier smoothly but clamp inside the current line.
+ // Compute whether the selection handles are currently on the same line, and,
+ // in this particular case, whether the selected text is right to left.
+ final boolean sameLineSelection = otherHandleOffset != -1
+ && lineNumber == layout.getLineForOffset(otherHandleOffset);
+ final boolean rtl = sameLineSelection
+ && (offset < otherHandleOffset)
+ != (getHorizontal(mTextView.getLayout(), offset)
+ < getHorizontal(mTextView.getLayout(), otherHandleOffset));
+
+ // Horizontally move the magnifier smoothly, clamp inside the current line / selection.
final int[] textViewLocationOnScreen = new int[2];
mTextView.getLocationOnScreen(textViewLocationOnScreen);
final float touchXInView = event.getRawX() - textViewLocationOnScreen[0];
- final float lineLeft = mTextView.getLayout().getLineLeft(lineNumber)
- + mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
- final float lineRight = mTextView.getLayout().getLineRight(lineNumber)
- + mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
+ float leftBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
+ float rightBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
+ if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_END) ^ rtl)) {
+ leftBound += getHorizontal(mTextView.getLayout(), otherHandleOffset);
+ } else {
+ leftBound += mTextView.getLayout().getLineLeft(lineNumber);
+ }
+ if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_START) ^ rtl)) {
+ rightBound += getHorizontal(mTextView.getLayout(), otherHandleOffset);
+ } else {
+ rightBound += mTextView.getLayout().getLineRight(lineNumber);
+ }
final float contentWidth = Math.round(mMagnifier.getWidth() / mMagnifier.getZoom());
- if (touchXInView < lineLeft - contentWidth / 2
- || touchXInView > lineRight + contentWidth / 2) {
- // The touch is too out of the bounds of the current line, so hide the magnifier.
+ if (touchXInView < leftBound - contentWidth / 2
+ || touchXInView > rightBound + contentWidth / 2) {
+ // The touch is too far from the current line / selection, so hide the magnifier.
return false;
}
- showPosInView.x = Math.max(lineLeft, Math.min(lineRight, touchXInView));
+ showPosInView.x = Math.max(leftBound, Math.min(rightBound, touchXInView));
// Vertically snap to middle of current line.
showPosInView.y = (mTextView.getLayout().getLineTop(lineNumber)
--
GitLab
From 550f658fa25433630bdbe092a607c30756426ff1 Mon Sep 17 00:00:00 2001
From: Adrian Roos
Date: Thu, 8 Mar 2018 20:08:19 +0100
Subject: [PATCH 024/488] Cutout: Add a multi cutout overlay
Bug: 74195186
Test: Developer Settings > Simulate a display with a cutout > Double display cutout
Change-Id: Iff621bd047c3c55d6e4f0e20eaa560706bfc4059
---
.../Android.mk | 14 ++++
.../AndroidManifest.xml | 26 +++++++
.../res/values/config.xml | 67 +++++++++++++++++++
.../res/values/strings.xml | 22 ++++++
4 files changed, 129 insertions(+)
create mode 100644 packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk
create mode 100644 packages/overlays/DisplayCutoutEmulationDoubleOverlay/AndroidManifest.xml
create mode 100644 packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
create mode 100644 packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk
new file mode 100644
index 00000000000..d83b30a8785
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := DisplayCutoutEmulationDouble
+LOCAL_CERTIFICATE := platform
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := DisplayCutoutEmulationDoubleOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/AndroidManifest.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/AndroidManifest.xml
new file mode 100644
index 00000000000..5d3385d1796
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/AndroidManifest.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
new file mode 100644
index 00000000000..ca261f98cfa
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+ M 0,0
+ L -72, 0
+ L -69.9940446283, 20.0595537175
+ C -69.1582133885, 28.4178661152 -65.2, 32.0 -56.8, 32.0
+ L 56.8, 32.0
+ C 65.2, 32.0 69.1582133885, 28.4178661152 69.9940446283, 20.0595537175
+ L 72, 0
+ Z
+ @bottom
+ M 0,0
+ L -72, 0
+ L -69.9940446283, -20.0595537175
+ C -69.1582133885, -28.4178661152 -65.2, -32.0 -56.8, -32.0
+ L 56.8, -32.0
+ C 65.2, -32.0 69.1582133885, -28.4178661152 69.9940446283, -20.0595537175
+ L 72, 0
+ Z
+ @dp
+
+
+
+ true
+
+
+ 48dp
+ 28dp
+
+ 48dp
+
+ 176dp
+
+
+
+
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml
new file mode 100644
index 00000000000..68c2dcbbe3f
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ Double display cutout
+
+
+
--
GitLab
From 5a6f3264465ebe54538731e27c97b587ebde1871 Mon Sep 17 00:00:00 2001
From: Michael Wright
Date: Fri, 9 Mar 2018 16:57:13 +0000
Subject: [PATCH 025/488] Fix up brightness docs.
Uncapitalize LUX in the docs to be consistent with naming.
Bug: 74328541
Test: N/A - doc change
Change-Id: I1484748a9325b49b7e4885b064546392c3bb1b78
---
core/res/res/values/config.xml | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f1c9f676fd5..7e6c1b990c9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1277,7 +1277,7 @@
in darkness (although they may not be visible in a bright room). -->
1
-
-
3.5G
+
+ 3.5G+
+
4G
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 487d1c5880a..a0466754eb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -205,13 +205,15 @@ public class MobileSignalController extends SignalController<
}
MobileIconGroup hGroup = TelephonyIcons.THREE_G;
+ MobileIconGroup hPlusGroup = TelephonyIcons.THREE_G;
if (mConfig.hspaDataDistinguishable) {
hGroup = TelephonyIcons.H;
+ hPlusGroup = TelephonyIcons.H_PLUS;
}
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hGroup);
+ mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hPlusGroup);
if (mConfig.show4gForLte) {
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 53637425401..2258fa25180 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -884,6 +884,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
datatype.equals("e") ? TelephonyIcons.E :
datatype.equals("g") ? TelephonyIcons.G :
datatype.equals("h") ? TelephonyIcons.H :
+ datatype.equals("h+") ? TelephonyIcons.H_PLUS :
datatype.equals("lte") ? TelephonyIcons.LTE :
datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS :
datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED :
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 986abef1003..7e6fe022644 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -28,7 +28,6 @@ class TelephonyIcons {
static final int ICON_G = R.drawable.ic_g_mobiledata;
static final int ICON_E = R.drawable.ic_e_mobiledata;
static final int ICON_H = R.drawable.ic_h_mobiledata;
- // TODO: add logic to insert H+ icon
static final int ICON_H_PLUS = R.drawable.ic_h_plus_mobiledata;
static final int ICON_3G = R.drawable.ic_3g_mobiledata;
static final int ICON_4G = R.drawable.ic_4g_mobiledata;
@@ -135,6 +134,19 @@ class TelephonyIcons {
TelephonyIcons.ICON_H,
false);
+ static final MobileIconGroup H_PLUS = new MobileIconGroup(
+ "H+",
+ null,
+ null,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+ 0, 0,
+ 0,
+ 0,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+ R.string.data_connection_3_5g_plus,
+ TelephonyIcons.ICON_H_PLUS,
+ false);
+
static final MobileIconGroup FOUR_G = new MobileIconGroup(
"4G",
null,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 8629799faea..365a9b28e8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -74,6 +74,17 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest {
verifyDataIndicators(TelephonyIcons.ICON_H);
}
+
+ @Test
+ public void testHspaPlusDataIcon() {
+ setupDefaultSignal();
+ updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.NETWORK_TYPE_HSPAP);
+
+ verifyDataIndicators(TelephonyIcons.ICON_H_PLUS);
+ }
+
+
@Test
public void testWfcNoDataIcon() {
setupDefaultSignal();
--
GitLab
From 12f867ca9856749c164f12df4bbbdc6330921fac Mon Sep 17 00:00:00 2001
From: Seigo Nonaka
Date: Thu, 8 Mar 2018 09:15:46 -0800
Subject: [PATCH 028/488] Add selectable text view perf test for random text
The performance characteristics are quite different if selection is
enabled. Good to add selectable random text case for reference.
This CL also fixes makeMeasureSpec miss usage.
android.widget.TextViewPrecomputedTextPerfTest:
newLayout_PrecomputedText : 758,899
newLayout_PrecomputedText_Selectable: 17,923,065
newLayout_RandomText : 17,059,504
newLayout_RandomText_Selectable : 18,523,234
onDraw_PrecomputedText : 4,097,640
onDraw_PrecomputedText_Selectable : 17,733,448
onDraw_RandomText : 17,941,208
onDraw_RandomText_Selectable : 18,948,912
onMeasure_PrecomputedText : 781,546
onMeasure_PrecomputedText_Selectable: 18,423,652
onMeasure_RandomText : 18,067,749
onMeasure_RandomText_Selectable : 19,364,439
setText_PrecomputedText : 91,383
setText_PrecomputedText_Selectable : 161,088
setText_RandomText : 11,142
setText_RandomText_Selectable : 54,596
Bug: 72998298
Test: N/A
Change-Id: I8c04fd972897eb804be42adff883df13d87bf11e
---
.../TextViewPrecomputedTextPerfTest.java | 115 +++++++++++++++---
1 file changed, 100 insertions(+), 15 deletions(-)
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
index 55b97e7675f..dc34b7fe057 100644
--- a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
@@ -116,6 +116,26 @@ public class TextViewPrecomputedTextPerfTest {
}
}
+ @Test
+ public void testNewLayout_RandomText_Selectable() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ BoringLayout.Metrics metrics = new BoringLayout.Metrics();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final TextView textView = new TextView(getContext());
+ textView.setTextIsSelectable(true);
+ textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
+ textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
+ textView.setText(text);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.makeNewLayout(TEXT_WIDTH, TEXT_WIDTH, UNKNOWN_BORING, UNKNOWN_BORING,
+ TEXT_WIDTH, false);
+ }
+ }
+
@Test
public void testNewLayout_PrecomputedText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
@@ -178,6 +198,24 @@ public class TextViewPrecomputedTextPerfTest {
}
}
+ @Test
+ public void testSetText_RandomText_Selectable() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ BoringLayout.Metrics metrics = new BoringLayout.Metrics();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final TextView textView = new TextView(getContext());
+ textView.setTextIsSelectable(true);
+ textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
+ textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.setText(text);
+ }
+ }
+
@Test
public void testSetText_PrecomputedText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
@@ -222,8 +260,8 @@ public class TextViewPrecomputedTextPerfTest {
@Test
public void testOnMeasure_RandomText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH);
- int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
+ int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
@@ -239,11 +277,32 @@ public class TextViewPrecomputedTextPerfTest {
}
}
+ @Test
+ public void testOnMeasure_RandomText_Selectable() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
+ int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final TestableTextView textView = new TestableTextView(getContext());
+ textView.setTextIsSelectable(true);
+ textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
+ textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
+ textView.setText(text);
+ textView.nullLayouts();
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.onMeasure(width, height);
+ }
+ }
+
@Test
public void testOnMeasure_PrecomputedText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH);
- int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
+ int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
@@ -265,8 +324,8 @@ public class TextViewPrecomputedTextPerfTest {
@Test
public void testOnMeasure_PrecomputedText_Selectable() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH);
- int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
+ int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
@@ -289,8 +348,8 @@ public class TextViewPrecomputedTextPerfTest {
@Test
public void testOnDraw_RandomText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH);
- int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
+ int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
@@ -299,8 +358,34 @@ public class TextViewPrecomputedTextPerfTest {
textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
textView.setText(text);
+ textView.measure(width, height);
+ textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
+ final DisplayListCanvas c = node.start(
+ textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
- textView.onMeasure(width, height);
+ Canvas.freeTextLayoutCaches();
+ state.resumeTiming();
+
+ textView.onDraw(c);
+ }
+ }
+
+ @Test
+ public void testOnDraw_RandomText_Selectable() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
+ int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ final RenderNode node = RenderNode.create("benchmark", null);
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+ final TestableTextView textView = new TestableTextView(getContext());
+ textView.setTextIsSelectable(true);
+ textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
+ textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
+ textView.setText(text);
+ textView.measure(width, height);
+ textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
final DisplayListCanvas c = node.start(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
@@ -314,8 +399,8 @@ public class TextViewPrecomputedTextPerfTest {
@Test
public void testOnDraw_PrecomputedText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH);
- int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
+ int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
@@ -327,8 +412,8 @@ public class TextViewPrecomputedTextPerfTest {
final TestableTextView textView = new TestableTextView(getContext());
textView.setTextMetricsParams(params);
textView.setText(text);
- textView.nullLayouts();
- textView.onMeasure(width, height);
+ textView.measure(width, height);
+ textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
final DisplayListCanvas c = node.start(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
@@ -356,8 +441,8 @@ public class TextViewPrecomputedTextPerfTest {
textView.setTextIsSelectable(true);
textView.setTextMetricsParams(params);
textView.setText(text);
- textView.nullLayouts();
- textView.onMeasure(width, height);
+ textView.measure(width, height);
+ textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
final DisplayListCanvas c = node.start(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
--
GitLab
From f3523ec5242f90f9608d7f860144f58ef5707b10 Mon Sep 17 00:00:00 2001
From: Seigo Nonaka
Date: Tue, 6 Mar 2018 13:38:11 -0800
Subject: [PATCH 029/488] Unhide getWeight of Typeface
Bug: 64852739
Test: atest CtsWidgetTestCases:EditTextTest
CtsWidgetTestCases:TextViewFadingEdgeTest
FrameworksCoreTests:TextViewFallbackLineSpacingTest
FrameworksCoreTests:TextViewTest FrameworksCoreTests:TypefaceTest
CtsGraphicsTestCases:TypefaceTest CtsWidgetTestCases:TextViewTest
CtsTextTestCases FrameworksCoreTests:android.text
Change-Id: Ic360cee7d57b38f3b92ecb68ab6bd46d961c3232
---
api/current.txt | 1 +
graphics/java/android/graphics/Typeface.java | 6 ++----
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/api/current.txt b/api/current.txt
index 2875e34de04..413003be26d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14436,6 +14436,7 @@ package android.graphics {
method public static android.graphics.Typeface createFromFile(java.lang.String);
method public static android.graphics.Typeface defaultFromStyle(int);
method public int getStyle();
+ method public int getWeight();
method public final boolean isBold();
method public final boolean isItalic();
field public static final int BOLD = 1; // 0x1
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index f27c11dbf73..e31a440dbfe 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -167,10 +167,8 @@ public class Typeface {
nativeSetDefault(t.native_instance);
}
- // TODO: Make this public API. (b/64852739)
- /** @hide */
- @VisibleForTesting
- public int getWeight() {
+ /** Returns the typeface's weight value */
+ public @IntRange(from = 0, to = 1000) int getWeight() {
return mWeight;
}
--
GitLab
From 62b01c7d26d6fc1d523f96dfd883ddffcd929d58 Mon Sep 17 00:00:00 2001
From: Wonsik Kim
Date: Fri, 9 Mar 2018 10:12:59 -0800
Subject: [PATCH 030/488] Implement CodecProfileLevel.{equals|hashCode}
Bug: 74435947
Test: atest CtsMediaTestCases:MediaCodecListTest
Change-Id: Ia77182538c5a151bb561f7d273f7cbaa29671a4c
---
media/java/android/media/MediaCodecInfo.java | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 44d909972e3..e6a8d015813 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -3078,6 +3078,23 @@ public final class MediaCodecInfo {
* {@link VideoCapabilities} to determine the codec capabilities.
*/
public int level;
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof CodecProfileLevel) {
+ CodecProfileLevel other = (CodecProfileLevel)obj;
+ return other.profile == profile && other.level == level;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Long.hashCode(((long)profile << Integer.SIZE) | level);
+ }
};
/**
--
GitLab
From 9219b31067f0498c1a9872460249e7a144a9e0c3 Mon Sep 17 00:00:00 2001
From: Tarandeep Singh
Date: Thu, 8 Mar 2018 17:05:02 -0800
Subject: [PATCH 031/488] Revert "Revert "Remove a compat hack
SurfaceView#setWindowType()""
This reverts commit 9309c19513ef569043cfd08deae78e04d5eb5c24.
Reason for revert: We can now remove the deprecated method. Compat hack
is no longer required for keyboards.
Fixes: 62054282
Test: Manually flashed and verified keyboard apps work.
Change-Id: Iae0c82b6fd3fd5930e9eea3216fab76925839e4d
---
core/java/android/view/SurfaceView.java | 26 -------------------------
1 file changed, 26 deletions(-)
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 4a9da4a6672..7213923415b 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,7 +16,6 @@
package android.view;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER;
import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER;
@@ -877,31 +876,6 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
return callbacks;
}
- /**
- * This method still exists only for compatibility reasons because some applications have relied
- * on this method via reflection. See Issue 36345857 for details.
- *
- * @deprecated No platform code is using this method anymore.
- * @hide
- */
- @Deprecated
- public void setWindowType(int type) {
- if (getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
- throw new UnsupportedOperationException(
- "SurfaceView#setWindowType() has never been a public API.");
- }
-
- if (type == TYPE_APPLICATION_PANEL) {
- Log.e(TAG, "If you are calling SurfaceView#setWindowType(TYPE_APPLICATION_PANEL) "
- + "just to make the SurfaceView to be placed on top of its window, you must "
- + "call setZOrderOnTop(true) instead.", new Throwable());
- setZOrderOnTop(true);
- return;
- }
- Log.e(TAG, "SurfaceView#setWindowType(int) is deprecated and now does nothing. "
- + "type=" + type, new Throwable());
- }
-
private void runOnUiThread(Runnable runnable) {
Handler handler = getHandler();
if (handler != null && handler.getLooper() != Looper.myLooper()) {
--
GitLab
From 3c0415aeb812b05a0c9667a9ce1198840c98dabe Mon Sep 17 00:00:00 2001
From: Jeff Davidson
Date: Fri, 23 Feb 2018 15:27:46 -0800
Subject: [PATCH 032/488] Allow carrier privileged apps to access
Telephony/Subscription APIs.
-All public APIs in TelephonyManager which require READ_PHONE_STATE
will now also be documented to accept carrier privileged callers as
well. (One exception is the change callbacks in each, which will be
addressed in a separate CL).
-For SubscriptionManager, callers without READ_PHONE_STATE will now be
able to access the subscription list; however, the resulting list will
be filtered to only include subscriptions for which the caller has
carrier privileges.
-All @see references to hasCarrierPrivileges have been removed in
favor of an inline {@link}. The @see section is set apart from the
rest of the Javadoc and thus appears out of context of where it's
actually relevant; moreover, it is often placed in the middle of a
line which makes it invalid. Using {@link} inlines the reference where
it's actually relevant.
-@SuppressAutodoc is added to any public method which has a
@RequiresPermission declaration that isn't a sufficient description of
the allowed callers, i.e. for APIs which accept carrier-privileged
callers, or the default dialer app or other exceptional cases. This
ensures redundant (but incorrect) requires permission declarations
aren't autogenerated.
Bug: 70041899
Test: TreeHugger, unit tests in topic
Change-Id: Ia5cc145c19d99fe2b87e3425bb95281980edef6f
Merged-In: Ia5cc145c19d99fe2b87e3425bb95281980edef6f
(cherry picked from commit bc10ce1efec7819d67cbd4b457ef91ce9db062cb)
---
.../com/android/server/TelephonyRegistry.java | 12 +-
.../telephony/SubscriptionManager.java | 35 +-
.../android/telephony/TelephonyManager.java | 344 ++++++++++--------
.../telephony/TelephonyPermissions.java | 83 ++++-
4 files changed, 300 insertions(+), 174 deletions(-)
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 3927ebd593b..62e82a064db 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -394,8 +394,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
+ " callback.asBinder=" + callback.asBinder());
}
+ // TODO(b/70041899): Find a way to make this work for carrier-privileged callers.
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mContext, callingPackage, "addOnSubscriptionsChangedListener")) {
+ mContext, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage,
+ "addOnSubscriptionsChangedListener")) {
return;
}
@@ -686,8 +688,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private boolean canReadPhoneState(String callingPackage, String message) {
try {
+ // TODO(b/70041899): Find a way to make this work for carrier-privileged callers.
return TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mContext, callingPackage, message);
+ mContext, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, message);
} catch (SecurityException e) {
return false;
}
@@ -1735,8 +1738,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mContext, callingPackage, message)) {
+ // TODO(b/70041899): Find a way to make this work for carrier-privileged callers.
+ if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, message)) {
return false;
}
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 4a6143788cc..ef66ed7ae06 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.BroadcastOptions;
@@ -42,7 +43,6 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.ServiceManager.ServiceNotFoundException;
import android.util.DisplayMetrics;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
@@ -59,9 +59,6 @@ import java.util.concurrent.TimeUnit;
/**
* SubscriptionManager is the application interface to SubscriptionController
* and provides information about the current Telephony Subscriptions.
- *
- * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE unless otherwise
- * specified.
*/
@SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
public class SubscriptionManager {
@@ -612,6 +609,8 @@ public class SubscriptionManager {
* @param listener an instance of {@link OnSubscriptionsChangedListener} with
* onSubscriptionsChanged overridden.
*/
+ // TODO(b/70041899): Find a way to extend this to carrier-privileged apps.
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
String pkgName = mContext != null ? mContext.getOpPackageName() : "";
if (DBG) {
@@ -660,9 +659,15 @@ public class SubscriptionManager {
/**
* Get the active SubscriptionInfo with the input subId.
*
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ *
* @param subId The unique SubscriptionInfo key in database.
* @return SubscriptionInfo, maybe null if its not active.
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public SubscriptionInfo getActiveSubscriptionInfo(int subId) {
if (VDBG) logd("[getActiveSubscriptionInfo]+ subId=" + subId);
if (!isValidSubscriptionId(subId)) {
@@ -716,9 +721,16 @@ public class SubscriptionManager {
/**
* Get the active SubscriptionInfo associated with the slotIndex
+ *
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ *
* @param slotIndex the slot which the subscription is inserted
* @return SubscriptionInfo, maybe null if its not active
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex) {
if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIndex=" + slotIndex);
if (!isValidSlotIndex(slotIndex)) {
@@ -770,6 +782,11 @@ public class SubscriptionManager {
* Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted
* by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}.
*
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}). In the latter case, only records accessible
+ * to the calling app are returned.
+ *
* @return Sorted list of the currently {@link SubscriptionInfo} records available on the device.
*
*
@@ -786,6 +803,8 @@ public class SubscriptionManager {
*
*
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public List getActiveSubscriptionInfoList() {
List result = null;
@@ -928,10 +947,18 @@ public class SubscriptionManager {
}
/**
+ *
+ * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}). In the latter case, the count will include
+ * only those subscriptions accessible to the caller.
+ *
* @return the current number of active subscriptions. There is no guarantee the value
* returned by this method will be the same as the length of the list returned by
* {@link #getActiveSubscriptionInfoList}.
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getActiveSubscriptionInfoCount() {
int result = 0;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index aa76e9d554b..91f04f94b94 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressAutoDoc;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -53,7 +54,6 @@ import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsMmTelFeature;
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
-import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.Log;
@@ -1114,7 +1114,11 @@ public class TelephonyManager {
* Returns the software version number for the device, for example,
* the IMEI/SV for GSM phones. Return null if the software version is
* not available.
+ *
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getDeviceSoftwareVersion() {
return getDeviceSoftwareVersion(getSlotIndex());
@@ -1146,10 +1150,14 @@ public class TelephonyManager {
* Returns the unique device ID, for example, the IMEI for GSM and the MEID
* or ESN for CDMA phones. Return null if device ID is not available.
*
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
* @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns
* MEID for CDMA.
*/
@Deprecated
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getDeviceId() {
try {
@@ -1168,12 +1176,16 @@ public class TelephonyManager {
* Returns the unique device ID of a subscription, for example, the IMEI for
* GSM and the MEID for CDMA phones. Return null if device ID is not available.
*
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
* @param slotIndex of which deviceID is returned
*
* @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns
* MEID for CDMA.
*/
@Deprecated
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getDeviceId(int slotIndex) {
// FIXME this assumes phoneId == slotIndex
@@ -1192,7 +1204,11 @@ public class TelephonyManager {
/**
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
+ *
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getImei() {
return getImei(getSlotIndex());
@@ -1202,8 +1218,12 @@ public class TelephonyManager {
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
* @param slotIndex of which IMEI is returned
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getImei(int slotIndex) {
ITelephony telephony = getITelephony();
@@ -1220,7 +1240,11 @@ public class TelephonyManager {
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
+ *
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getMeid() {
return getMeid(getSlotIndex());
@@ -1229,8 +1253,12 @@ public class TelephonyManager {
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
* @param slotIndex of which MEID is returned
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getMeid(int slotIndex) {
ITelephony telephony = getITelephony();
@@ -1247,10 +1275,11 @@ public class TelephonyManager {
/**
* Returns the Network Access Identifier (NAI). Return null if NAI is not available.
- *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getNai() {
return getNaiBySubscriberId(getSubId());
@@ -1751,6 +1780,7 @@ public class TelephonyManager {
* @see #createForSubscriptionId(int)
* @see #createForPhoneAccountHandle(PhoneAccountHandle)
*/
+ // TODO(b/73136824, b/70041899): Permit carrier-privileged callers as well.
@WorkerThread
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public PersistableBundle getCarrierConfig() {
@@ -1949,6 +1979,9 @@ public class TelephonyManager {
* If this object has been created with {@link #createForSubscriptionId}, applies to the given
* subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
*
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
* @return the network type
*
* @see #NETWORK_TYPE_UNKNOWN
@@ -1968,6 +2001,7 @@ public class TelephonyManager {
* @see #NETWORK_TYPE_EHRPD
* @see #NETWORK_TYPE_HSPAP
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getDataNetworkType() {
return getDataNetworkType(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
@@ -2002,7 +2036,11 @@ public class TelephonyManager {
/**
* Returns the NETWORK_TYPE_xxxx for voice
+ *
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public int getVoiceNetworkType() {
return getVoiceNetworkType(getSubId());
@@ -2588,7 +2626,11 @@ public class TelephonyManager {
/**
* Returns the serial number of the SIM, if applicable. Return null if it is
* unavailable.
+ *
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getSimSerialNumber() {
return getSimSerialNumber(getSubId());
@@ -2713,7 +2755,11 @@ public class TelephonyManager {
/**
* Returns the unique subscriber ID, for example, the IMSI for a GSM phone.
* Return null if it is unavailable.
+ *
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getSubscriberId() {
return getSubscriberId(getSubId());
@@ -2877,7 +2923,11 @@ public class TelephonyManager {
/**
* Returns the Group Identifier Level1 for a GSM phone.
* Return null if it is unavailable.
+ *
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getGroupIdLevel1() {
try {
@@ -2918,9 +2968,15 @@ public class TelephonyManager {
/**
* Returns the phone number string for line 1, for example, the MSISDN
* for a GSM phone. Return null if it is unavailable.
- *
- * The default SMS app can also use this.
+ *
+ *
Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE},
+ * {@link android.Manifest.permission#READ_SMS READ_SMS},
+ * {@link android.Manifest.permission#READ_PHONE_NUMBERS READ_PHONE_NUMBERS},
+ * that the caller is the default SMS app,
+ * or that the caller has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges or default SMS app
@RequiresPermission(anyOf = {
android.Manifest.permission.READ_PHONE_STATE,
android.Manifest.permission.READ_SMS,
@@ -2975,8 +3031,7 @@ public class TelephonyManager {
* change the actual MSISDN/MDN. To unset alphatag or number, pass in a null
* value.
*
- *
Requires that the calling app has carrier privileges.
- * @see #hasCarrierPrivileges
+ *
Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param alphaTag alpha-tagging of the dailing nubmer
* @param number The dialing number
@@ -2992,8 +3047,7 @@ public class TelephonyManager {
* change the actual MSISDN/MDN. To unset alphatag or number, pass in a null
* value.
*
- *
Requires that the calling app has carrier privileges.
- * @see #hasCarrierPrivileges
+ *
Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId the subscriber that the alphatag and dialing number belongs to.
* @param alphaTag alpha-tagging of the dailing nubmer
@@ -3112,7 +3166,11 @@ public class TelephonyManager {
/**
* Returns the voice mail number. Return null if it is unavailable.
+ *
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getVoiceMailNumber() {
return getVoiceMailNumber(getSubId());
@@ -3173,8 +3231,7 @@ public class TelephonyManager {
/**
* Sets the voice mail number.
*
- *
Requires that the calling app has carrier privileges.
- * @see #hasCarrierPrivileges
+ *
Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param alphaTag The alpha tag to display.
* @param number The voicemail number.
@@ -3186,8 +3243,7 @@ public class TelephonyManager {
/**
* Sets the voicemail number for the given subscriber.
*
- *
Requires that the calling app has carrier privileges.
- * @see #hasCarrierPrivileges
+ *
Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId The subscription id.
* @param alphaTag The alpha tag to display.
@@ -3208,9 +3264,9 @@ public class TelephonyManager {
/**
* Enables or disables the visual voicemail client for a phone account.
*
- *
Requires that the calling app is the default dialer, or has carrier privileges, or
- * has permission {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
- * @see #hasCarrierPrivileges
+ *
Requires that the calling app is the default dialer, or has carrier privileges (see
+ * {@link #hasCarrierPrivileges}), or has permission
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
*
* @param phoneAccountHandle the phone account to change the client state
* @param enabled the new state of the client
@@ -3273,11 +3329,15 @@ public class TelephonyManager {
* to the TelephonyManager. Returns {@code null} when there is no package responsible for
* processing visual voicemail for the subscription.
*
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
* @see #createForSubscriptionId(int)
* @see #createForPhoneAccountHandle(PhoneAccountHandle)
* @see VisualVoicemailService
*/
@Nullable
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getVisualVoicemailPackageName() {
try {
@@ -3520,15 +3580,14 @@ public class TelephonyManager {
* Sets the voice activation state
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges.
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
+ * calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param activationState The voice activation state
* @see #SIM_ACTIVATION_STATE_UNKNOWN
* @see #SIM_ACTIVATION_STATE_ACTIVATING
* @see #SIM_ACTIVATION_STATE_ACTIVATED
* @see #SIM_ACTIVATION_STATE_DEACTIVATED
- * @see #hasCarrierPrivileges
* @hide
*/
@SystemApi
@@ -3541,8 +3600,8 @@ public class TelephonyManager {
* Sets the voice activation state for the given subscriber.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges.
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
+ * calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId The subscription id.
* @param activationState The voice activation state of the given subscriber.
@@ -3550,7 +3609,6 @@ public class TelephonyManager {
* @see #SIM_ACTIVATION_STATE_ACTIVATING
* @see #SIM_ACTIVATION_STATE_ACTIVATED
* @see #SIM_ACTIVATION_STATE_DEACTIVATED
- * @see #hasCarrierPrivileges
* @hide
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@@ -3568,8 +3626,8 @@ public class TelephonyManager {
* Sets the data activation state
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges.
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
+ * calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param activationState The data activation state
* @see #SIM_ACTIVATION_STATE_UNKNOWN
@@ -3577,7 +3635,6 @@ public class TelephonyManager {
* @see #SIM_ACTIVATION_STATE_ACTIVATED
* @see #SIM_ACTIVATION_STATE_DEACTIVATED
* @see #SIM_ACTIVATION_STATE_RESTRICTED
- * @see #hasCarrierPrivileges
* @hide
*/
@SystemApi
@@ -3590,8 +3647,8 @@ public class TelephonyManager {
* Sets the data activation state for the given subscriber.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges.
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
+ * calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId The subscription id.
* @param activationState The data activation state of the given subscriber.
@@ -3600,7 +3657,6 @@ public class TelephonyManager {
* @see #SIM_ACTIVATION_STATE_ACTIVATED
* @see #SIM_ACTIVATION_STATE_DEACTIVATED
* @see #SIM_ACTIVATION_STATE_RESTRICTED
- * @see #hasCarrierPrivileges
* @hide
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@@ -3618,15 +3674,14 @@ public class TelephonyManager {
* Returns the voice activation state
*
*
Requires Permission:
- * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
- * Or the calling app has carrier privileges.
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @return voiceActivationState
* @see #SIM_ACTIVATION_STATE_UNKNOWN
* @see #SIM_ACTIVATION_STATE_ACTIVATING
* @see #SIM_ACTIVATION_STATE_ACTIVATED
* @see #SIM_ACTIVATION_STATE_DEACTIVATED
- * @see #hasCarrierPrivileges
* @hide
*/
@SystemApi
@@ -3639,8 +3694,8 @@ public class TelephonyManager {
* Returns the voice activation state for the given subscriber.
*
*
Requires Permission:
- * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
- * Or the calling app has carrier privileges.
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId The subscription id.
*
@@ -3649,7 +3704,6 @@ public class TelephonyManager {
* @see #SIM_ACTIVATION_STATE_ACTIVATING
* @see #SIM_ACTIVATION_STATE_ACTIVATED
* @see #SIM_ACTIVATION_STATE_DEACTIVATED
- * @see #hasCarrierPrivileges
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@@ -3668,8 +3722,8 @@ public class TelephonyManager {
* Returns the data activation state
*
*
Requires Permission:
- * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
- * Or the calling app has carrier privileges.
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @return dataActivationState for the given subscriber
* @see #SIM_ACTIVATION_STATE_UNKNOWN
@@ -3677,7 +3731,6 @@ public class TelephonyManager {
* @see #SIM_ACTIVATION_STATE_ACTIVATED
* @see #SIM_ACTIVATION_STATE_DEACTIVATED
* @see #SIM_ACTIVATION_STATE_RESTRICTED
- * @see #hasCarrierPrivileges
* @hide
*/
@SystemApi
@@ -3690,8 +3743,8 @@ public class TelephonyManager {
* Returns the data activation state for the given subscriber.
*
*
Requires Permission:
- * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
- * Or the calling app has carrier privileges.
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId The subscription id.
*
@@ -3701,7 +3754,6 @@ public class TelephonyManager {
* @see #SIM_ACTIVATION_STATE_ACTIVATED
* @see #SIM_ACTIVATION_STATE_DEACTIVATED
* @see #SIM_ACTIVATION_STATE_RESTRICTED
- * @see #hasCarrierPrivileges
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@@ -3749,7 +3801,11 @@ public class TelephonyManager {
/**
* Retrieves the alphabetic identifier associated with the voice
* mail number.
+ *
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getVoiceMailAlphaTag() {
return getVoiceMailAlphaTag(getSubId());
@@ -3778,9 +3834,8 @@ public class TelephonyManager {
}
/**
- * Send the special dialer code. The IPC caller must be the current default dialer or has
- * carrier privileges.
- * @see #hasCarrierPrivileges
+ * Send the special dialer code. The IPC caller must be the current default dialer or have
+ * carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param inputCode The special dialer code to send
*
@@ -4304,8 +4359,8 @@ public class TelephonyManager {
* Input parameters equivalent to TS 27.007 AT+CCHO command.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param AID Application id. See ETSI 102.221 and 101.220.
* @return an IccOpenLogicalChannelResponse object.
@@ -4322,8 +4377,8 @@ public class TelephonyManager {
* Input parameters equivalent to TS 27.007 AT+CCHO command.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param AID Application id. See ETSI 102.221 and 101.220.
* @param p2 P2 parameter (described in ISO 7816-4).
@@ -4339,8 +4394,8 @@ public class TelephonyManager {
* Input parameters equivalent to TS 27.007 AT+CCHO command.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId The subscription to use.
* @param AID Application id. See ETSI 102.221 and 101.220.
@@ -4365,8 +4420,8 @@ public class TelephonyManager {
* Input parameters equivalent to TS 27.007 AT+CCHC command.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param channel is the channel id to be closed as retruned by a successful
* iccOpenLogicalChannel.
@@ -4382,8 +4437,8 @@ public class TelephonyManager {
* Input parameters equivalent to TS 27.007 AT+CCHC command.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId The subscription to use.
* @param channel is the channel id to be closed as retruned by a successful
@@ -4408,8 +4463,8 @@ public class TelephonyManager {
* Input parameters equivalent to TS 27.007 AT+CGLA command.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param channel is the channel id to be closed as returned by a successful
* iccOpenLogicalChannel.
@@ -4435,8 +4490,8 @@ public class TelephonyManager {
* Input parameters equivalent to TS 27.007 AT+CGLA command.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId The subscription to use.
* @param channel is the channel id to be closed as returned by a successful
@@ -4471,8 +4526,8 @@ public class TelephonyManager {
* Input parameters equivalent to TS 27.007 AT+CSIM command.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param cla Class of the APDU command.
* @param instruction Instruction of the APDU command.
@@ -4496,8 +4551,8 @@ public class TelephonyManager {
* Input parameters equivalent to TS 27.007 AT+CSIM command.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId The subscription to use.
* @param cla Class of the APDU command.
@@ -4528,8 +4583,8 @@ public class TelephonyManager {
* Returns the response APDU for a command APDU sent through SIM_IO.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param fileID
* @param command
@@ -4548,8 +4603,8 @@ public class TelephonyManager {
* Returns the response APDU for a command APDU sent through SIM_IO.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId The subscription to use.
* @param fileID
@@ -4577,8 +4632,8 @@ public class TelephonyManager {
* Send ENVELOPE to the SIM and return the response.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param content String containing SAT/USAT response in hexadecimal
* format starting with command tag. See TS 102 223 for
@@ -4595,8 +4650,8 @@ public class TelephonyManager {
* Send ENVELOPE to the SIM and return the response.
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId The subscription to use.
* @param content String containing SAT/USAT response in hexadecimal
@@ -4621,10 +4676,10 @@ public class TelephonyManager {
/**
* Read one of the NV items defined in com.android.internal.telephony.RadioNVItems.
* Used for device configuration by some CDMA operators.
- *
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ *
Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param itemID the ID of the item to read.
* @return the NV item as a String, or null on any failure.
@@ -4647,10 +4702,10 @@ public class TelephonyManager {
/**
* Write one of the NV items defined in com.android.internal.telephony.RadioNVItems.
* Used for device configuration by some CDMA operators.
- *
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ *
Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param itemID the ID of the item to read.
* @param itemValue the value to write, as a String.
@@ -4674,10 +4729,10 @@ public class TelephonyManager {
/**
* Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
* Used for device configuration by some CDMA operators.
- *
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ *
Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param preferredRoamingList byte array containing the new PRL.
* @return true on success; false on any failure.
@@ -4701,10 +4756,10 @@ public class TelephonyManager {
* Perform the specified type of NV config reset. The radio will be taken offline
* and the device must be rebooted after the operation. Used for device
* configuration by some CDMA operators.
- *
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ *
Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param resetType reset type: 1: reload NV reset, 2: erase NV reset, 3: factory NV reset
* @return true on success; false on any failure.
@@ -5052,8 +5107,8 @@ public class TelephonyManager {
* Returns the response of authentication for the default subscription.
* Returns null if the authentication hasn't been successful
*
- *
Requires that the calling app has carrier privileges or READ_PRIVILEGED_PHONE_STATE
- * permission.
+ *
Requires Permission: READ_PRIVILEGED_PHONE_STATE or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param appType the icc application type, like {@link #APPTYPE_USIM}
* @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
@@ -5061,9 +5116,10 @@ public class TelephonyManager {
* @param data authentication challenge data, base64 encoded.
* See 3GPP TS 31.102 7.1.2 for more details.
* @return the response of authentication, or null if not available
- *
- * @see #hasCarrierPrivileges
*/
+ // TODO(b/73660190): This should probably require MODIFY_PHONE_STATE, not
+ // READ_PRIVILEGED_PHONE_STATE. It certainly shouldn't reference the permission in Javadoc since
+ // it's not public API.
public String getIccAuthentication(int appType, int authType, String data) {
return getIccAuthentication(getSubId(), appType, authType, data);
}
@@ -5072,7 +5128,7 @@ public class TelephonyManager {
* Returns the response of USIM Authentication for specified subId.
* Returns null if the authentication hasn't been successful
*
- *
Requires that the calling app has carrier privileges.
+ *
Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId subscription ID used for authentication
* @param appType the icc application type, like {@link #APPTYPE_USIM}
@@ -5081,8 +5137,6 @@ public class TelephonyManager {
* @param data authentication challenge data, base64 encoded.
* See 3GPP TS 31.102 7.1.2 for more details.
* @return the response of authentication, or null if not available
- *
- * @see #hasCarrierPrivileges
* @hide
*/
public String getIccAuthentication(int subId, int appType, int authType, String data) {
@@ -5103,8 +5157,12 @@ public class TelephonyManager {
* Returns an array of Forbidden PLMNs from the USIM App
* Returns null if the query fails.
*
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
* @return an array of forbidden PLMNs or null if not available
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String[] getForbiddenPlmns() {
return getForbiddenPlmns(getSubId(), APPTYPE_USIM);
@@ -5310,10 +5368,10 @@ public class TelephonyManager {
/**
* Get the preferred network type.
* Used for device configuration by some CDMA operators.
- *
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ *
Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @return the preferred network type, defined in RILConstants.java.
* @hide
@@ -5333,11 +5391,12 @@ public class TelephonyManager {
/**
* Sets the network selection mode to automatic.
- *
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ *
Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setNetworkSelectionModeAutomatic() {
try {
@@ -5353,15 +5412,14 @@ public class TelephonyManager {
}
/**
- * Perform a radio scan and return the list of avialble networks.
+ * Perform a radio scan and return the list of available networks.
*
* The return value is a list of the OperatorInfo of the networks found. Note that this
* scan can take a long time (sometimes minutes) to happen.
*
- *
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @hide
* TODO: Add an overload that takes no args.
@@ -5385,17 +5443,16 @@ public class TelephonyManager {
* This method is asynchronous, so the network scan results will be returned by callback.
* The returned NetworkScan will contain a callback method which can be used to stop the scan.
*
- *
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges.
- * @see #hasCarrierPrivileges()
+ *
Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param request Contains all the RAT with bands/channels that need to be scanned.
* @param executor The executor through which the callback should be invoked.
* @param callback Returns network scan results or errors.
* @return A NetworkScan obj which contains a callback which can be used to stop the scan.
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public NetworkScan requestNetworkScan(
NetworkScanRequest request, Executor executor,
@@ -5423,10 +5480,9 @@ public class TelephonyManager {
/**
* Ask the radio to connect to the input network and change selection mode to manual.
*
- *
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param operatorNumeric the PLMN ID of the network to select.
* @param persistSelection whether the selection will persist until reboot. If true, only allows
@@ -5434,6 +5490,7 @@ public class TelephonyManager {
* normal network selection next time.
* @return true on success; false on any failure.
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean setNetworkSelectionModeManual(String operatorNumeric, boolean persistSelection) {
try {
@@ -5453,10 +5510,10 @@ public class TelephonyManager {
/**
* Set the preferred network type.
* Used for device configuration by some CDMA operators.
- *
- * Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
- * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ *
Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId the id of the subscription to set the preferred network type for.
* @param networkType the preferred network type, defined in RILConstants.java.
@@ -5480,9 +5537,7 @@ public class TelephonyManager {
/**
* Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
*
- *
- * Requires that the calling app has carrier privileges.
- * @see #hasCarrierPrivileges
+ *
Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @return true on success; false on any failure.
*/
@@ -5493,9 +5548,7 @@ public class TelephonyManager {
/**
* Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
*
- *
- * Requires that the calling app has carrier privileges.
- * @see #hasCarrierPrivileges
+ *
Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @return true on success; false on any failure.
* @hide
@@ -5585,8 +5638,7 @@ public class TelephonyManager {
* brand value input. To unset the value, the same function should be
* called with a null brand value.
*
- *
Requires that the calling app has carrier privileges.
- * @see #hasCarrierPrivileges
+ *
Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param brand The brand name to display/set.
* @return true if the operation was executed correctly.
@@ -5603,8 +5655,7 @@ public class TelephonyManager {
* brand value input. To unset the value, the same function should be
* called with a null brand value.
*
- *
Requires that the calling app has carrier privileges.
- * @see #hasCarrierPrivileges
+ *
Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param subId The subscription to use.
* @param brand The brand name to display/set.
@@ -6258,15 +6309,15 @@ public class TelephonyManager {
* subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
- * calling app has carrier privileges.
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param enable Whether to enable mobile data.
*
- * @see #hasCarrierPrivileges
* @deprecated use {@link #setUserMobileDataEnabled(boolean)} instead.
*/
@Deprecated
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setDataEnabled(boolean enable) {
setUserMobileDataEnabled(enable);
@@ -6303,7 +6354,7 @@ public class TelephonyManager {
*
Requires one of the following permissions:
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE},
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the
- * calling app has carrier privileges.
+ * calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
*
Note that this does not take into account any data restrictions that may be present on the
* calling app. Such restrictions may be inspected with
@@ -6311,7 +6362,6 @@ public class TelephonyManager {
*
* @return true if mobile data is enabled.
*
- * @see #hasCarrierPrivileges
* @deprecated use {@link #isUserMobileDataEnabled()} instead.
*/
@Deprecated
@@ -7082,7 +7132,11 @@ public class TelephonyManager {
/**
* Returns the current {@link ServiceState} information.
+ *
+ *
Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public ServiceState getServiceState() {
return getServiceStateForSubscriber(getSubId());
@@ -7128,14 +7182,14 @@ public class TelephonyManager {
/**
* Sets the per-account voicemail ringtone.
*
- *
Requires that the calling app is the default dialer, or has carrier privileges, or has
- * permission {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+ *
Requires that the calling app is the default dialer, or has carrier privileges (see
+ * {@link #hasCarrierPrivileges}, or has permission
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
*
* @param phoneAccountHandle The handle for the {@link PhoneAccount} for which to set the
* voicemail ringtone.
* @param uri The URI for the ringtone to play when receiving a voicemail from a specific
* PhoneAccount.
- * @see #hasCarrierPrivileges
*
* @deprecated Use {@link android.provider.Settings#ACTION_CHANNEL_NOTIFICATION_SETTINGS}
* instead.
@@ -7173,14 +7227,14 @@ public class TelephonyManager {
/**
* Sets the per-account preference whether vibration is enabled for voicemail notifications.
*
- *
Requires that the calling app is the default dialer, or has carrier privileges, or has
- * permission {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+ *
Requires that the calling app is the default dialer, or has carrier privileges (see
+ * {@link #hasCarrierPrivileges}, or has permission
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
*
* @param phoneAccountHandle The handle for the {@link PhoneAccount} for which to set the
* voicemail vibration setting.
* @param enabled Whether to enable or disable vibration for voicemail notifications from a
* specific PhoneAccount.
- * @see #hasCarrierPrivileges
*
* @deprecated Use {@link android.provider.Settings#ACTION_CHANNEL_NOTIFICATION_SETTINGS}
* instead.
@@ -7601,12 +7655,10 @@ public class TelephonyManager {
* Otherwise, it applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
*
*
Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
- * calling app has carrier privileges.
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}.
*
* @param enable Whether to enable mobile data.
- *
- * @see #hasCarrierPrivileges
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setUserMobileDataEnabled(boolean enable) {
@@ -7624,15 +7676,13 @@ public class TelephonyManager {
*
Requires one of the following permissions:
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE},
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the
- * calling app has carrier privileges.
+ * calling app has carrier privileges (see {@link #hasCarrierPrivileges}.
*
*
Note that this does not take into account any data restrictions that may be present on the
* calling app. Such restrictions may be inspected with
* {@link ConnectivityManager#getRestrictBackgroundStatus}.
*
* @return true if mobile data is enabled.
- *
- * @see #hasCarrierPrivileges
*/
@RequiresPermission(anyOf = {
android.Manifest.permission.ACCESS_NETWORK_STATE,
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index da8471fa19e..a182f2be421 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -26,7 +26,8 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.ITelephony;
+
+import java.util.function.Supplier;
/** Utility class for Telephony permission enforcement. */
public final class TelephonyPermissions {
@@ -34,6 +35,9 @@ public final class TelephonyPermissions {
private static final boolean DBG = false;
+ private static final Supplier TELEPHONY_SUPPLIER = () ->
+ ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
+
private TelephonyPermissions() {}
/**
@@ -41,8 +45,8 @@ public final class TelephonyPermissions {
*
*
This method behaves in one of the following ways:
*
- *
return true: if the caller has either the READ_PRIVILEGED_PHONE_STATE permission or the
- * READ_PHONE_STATE runtime permission.
+ *
return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
+ * READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
*
throw SecurityException: if the caller didn't declare any of these permissions, or, for
* apps which support runtime permissions, if the caller does not currently have any of
* these permissions.
@@ -51,20 +55,30 @@ public final class TelephonyPermissions {
* manually (via AppOps). In this case we can't throw as it would break app compatibility,
* so we return false to indicate that the calling function should return dummy data.
*
+ *
+ *
Note: for simplicity, this method always returns false for callers using legacy
+ * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
+ * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
+ * devices.
+ *
+ * @param subId the subId of the relevant subscription; used to check carrier privileges. May be
+ * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} to skip this check for cases
+ * where it isn't relevant (hidden APIs, or APIs which are otherwise okay to leave
+ * inaccesible to carrier-privileged apps).
*/
public static boolean checkCallingOrSelfReadPhoneState(
- Context context, String callingPackage, String message) {
- return checkReadPhoneState(context, Binder.getCallingPid(), Binder.getCallingUid(),
+ Context context, int subId, String callingPackage, String message) {
+ return checkReadPhoneState(context, subId, Binder.getCallingPid(), Binder.getCallingUid(),
callingPackage, message);
}
/**
* Check whether the app with the given pid/uid can read phone state.
*
- *
This method behaves in one of the following ways:
+ *
This method behaves in one of the following ways:
*
- *
return true: if the caller has either the READ_PRIVILEGED_PHONE_STATE permission or the
- * READ_PHONE_STATE runtime permission.
+ *
return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
+ * READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
*
throw SecurityException: if the caller didn't declare any of these permissions, or, for
* apps which support runtime permissions, if the caller does not currently have any of
* these permissions.
@@ -73,9 +87,22 @@ public final class TelephonyPermissions {
* manually (via AppOps). In this case we can't throw as it would break app compatibility,
* so we return false to indicate that the calling function should return dummy data.
*
+ *
+ *
Note: for simplicity, this method always returns false for callers using legacy
+ * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
+ * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
+ * devices.
*/
public static boolean checkReadPhoneState(
- Context context, int pid, int uid, String callingPackage, String message) {
+ Context context, int subId, int pid, int uid, String callingPackage, String message) {
+ return checkReadPhoneState(
+ context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, message);
+ }
+
+ @VisibleForTesting
+ public static boolean checkReadPhoneState(
+ Context context, Supplier telephonySupplier, int subId, int pid, int uid,
+ String callingPackage, String message) {
try {
context.enforcePermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
@@ -83,8 +110,18 @@ public final class TelephonyPermissions {
// SKIP checking for run-time permission since caller has PRIVILEGED permission
return true;
} catch (SecurityException privilegedPhoneStateException) {
- context.enforcePermission(
- android.Manifest.permission.READ_PHONE_STATE, pid, uid, message);
+ try {
+ context.enforcePermission(
+ android.Manifest.permission.READ_PHONE_STATE, pid, uid, message);
+ } catch (SecurityException phoneStateException) {
+ // If we don't have the runtime permission, but do have carrier privileges, that
+ // suffices for reading phone state.
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ enforceCarrierPrivilege(telephonySupplier, subId, uid, message);
+ return true;
+ }
+ throw phoneStateException;
+ }
}
// We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
@@ -101,14 +138,16 @@ public final class TelephonyPermissions {
* default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS can also read phone numbers.
*/
public static boolean checkCallingOrSelfReadPhoneNumber(
- Context context, String callingPackage, String message) {
+ Context context, int subId, String callingPackage, String message) {
return checkReadPhoneNumber(
- context, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message);
+ context, TELEPHONY_SUPPLIER, subId, Binder.getCallingPid(), Binder.getCallingUid(),
+ callingPackage, message);
}
@VisibleForTesting
public static boolean checkReadPhoneNumber(
- Context context, int pid, int uid, String callingPackage, String message) {
+ Context context, Supplier telephonySupplier, int subId, int pid, int uid,
+ String callingPackage, String message) {
// Default SMS app can always read it.
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
if (appOps.noteOp(AppOpsManager.OP_WRITE_SMS, uid, callingPackage) ==
@@ -121,7 +160,8 @@ public final class TelephonyPermissions {
// First, check if we can read the phone state.
try {
- return checkReadPhoneState(context, pid, uid, callingPackage, message);
+ return checkReadPhoneState(
+ context, telephonySupplier, subId, pid, uid, callingPackage, message);
} catch (SecurityException readPhoneStateSecurityException) {
}
// Can be read with READ_SMS too.
@@ -186,16 +226,21 @@ public final class TelephonyPermissions {
}
private static void enforceCarrierPrivilege(int subId, int uid, String message) {
- if (getCarrierPrivilegeStatus(subId, uid) !=
+ enforceCarrierPrivilege(TELEPHONY_SUPPLIER, subId, uid, message);
+ }
+
+ private static void enforceCarrierPrivilege(
+ Supplier telephonySupplier, int subId, int uid, String message) {
+ if (getCarrierPrivilegeStatus(telephonySupplier, subId, uid) !=
TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
if (DBG) Rlog.e(LOG_TAG, "No Carrier Privilege.");
throw new SecurityException(message);
}
}
- private static int getCarrierPrivilegeStatus(int subId, int uid) {
- ITelephony telephony =
- ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ private static int getCarrierPrivilegeStatus(
+ Supplier telephonySupplier, int subId, int uid) {
+ ITelephony telephony = telephonySupplier.get();
try {
if (telephony != null) {
return telephony.getCarrierPrivilegeStatusForUid(subId, uid);
--
GitLab
From d7a485b6e6496bad88fcd29afa15f31bfb9b2478 Mon Sep 17 00:00:00 2001
From: Jeff Davidson
Date: Wed, 28 Feb 2018 10:20:55 -0800
Subject: [PATCH 033/488] Allow carrier-privileged apps to access voicemail
provider.
Bug: 70041899
Test: TreeHugger + tests in CL topic
Change-Id: I437695ca42e42c84a9a3027d9314a7f7175b978d
Merged-In: I437695ca42e42c84a9a3027d9314a7f7175b978d
(cherry picked from commit 5861cd588b49042a90d0a59967fe607cabb166bd)
---
core/java/android/provider/VoicemailContract.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index c568b6fbe0c..140336e9335 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -49,7 +49,8 @@ import java.util.List;
*
*
*
The minimum permission needed to access this content provider is
- * {@link android.Manifest.permission#ADD_VOICEMAIL}
+ * {@link android.Manifest.permission#ADD_VOICEMAIL} or carrier privileges (see
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
*
*
Voicemails are inserted by what is called as a "voicemail source"
* application, which is responsible for syncing voicemail data between a remote
--
GitLab
From 82a2a874749fb0c94c32bc1fae354820e275bc43 Mon Sep 17 00:00:00 2001
From: Marco Nelissen
Date: Tue, 7 Nov 2017 13:52:02 -0800
Subject: [PATCH 034/488] Rework thumbnail cleanup
Bug: 63766886
Test: ran CTS tests
Change-Id: I1f92bb014e275eafe3f42aef1f8c817f187c6608
Merged-In: I1f92bb014e275eafe3f42aef1f8c817f187c6608
---
core/java/android/provider/MediaStore.java | 4 +-
media/java/android/media/MediaScanner.java | 52 --------------------
media/java/android/media/MiniThumbFile.java | 54 ++++++++++++++++++++-
3 files changed, 54 insertions(+), 56 deletions(-)
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index de19f819295..b17657b43db 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -678,8 +678,8 @@ public final class MediaStore {
// Log.v(TAG, "getThumbnail: origId="+origId+", kind="+kind+", isVideo="+isVideo);
// If the magic is non-zero, we simply return thumbnail if it does exist.
// querying MediaProvider and simply return thumbnail.
- MiniThumbFile thumbFile = new MiniThumbFile(isVideo ? Video.Media.EXTERNAL_CONTENT_URI
- : Images.Media.EXTERNAL_CONTENT_URI);
+ MiniThumbFile thumbFile = MiniThumbFile.instance(
+ isVideo ? Video.Media.EXTERNAL_CONTENT_URI : Images.Media.EXTERNAL_CONTENT_URI);
Cursor c = null;
try {
long magic = thumbFile.getMagic(origId);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 0fafe4b19a4..4c113d946d1 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -323,7 +323,6 @@ public class MediaScanner implements AutoCloseable {
private final Uri mAudioUri;
private final Uri mVideoUri;
private final Uri mImagesUri;
- private final Uri mThumbsUri;
private final Uri mPlaylistsUri;
private final Uri mFilesUri;
private final Uri mFilesUriNoNotify;
@@ -419,7 +418,6 @@ public class MediaScanner implements AutoCloseable {
mAudioUri = Audio.Media.getContentUri(volumeName);
mVideoUri = Video.Media.getContentUri(volumeName);
mImagesUri = Images.Media.getContentUri(volumeName);
- mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
mFilesUri = Files.getContentUri(volumeName);
mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
@@ -1283,53 +1281,6 @@ public class MediaScanner implements AutoCloseable {
}
}
- private void pruneDeadThumbnailFiles() {
- HashSet existingFiles = new HashSet();
- String directory = "/sdcard/DCIM/.thumbnails";
- String [] files = (new File(directory)).list();
- Cursor c = null;
- if (files == null)
- files = new String[0];
-
- for (int i = 0; i < files.length; i++) {
- String fullPathString = directory + "/" + files[i];
- existingFiles.add(fullPathString);
- }
-
- try {
- c = mMediaProvider.query(
- mThumbsUri,
- new String [] { "_data" },
- null,
- null,
- null, null);
- Log.v(TAG, "pruneDeadThumbnailFiles... " + c);
- if (c != null && c.moveToFirst()) {
- do {
- String fullPathString = c.getString(0);
- existingFiles.remove(fullPathString);
- } while (c.moveToNext());
- }
-
- for (String fileToDelete : existingFiles) {
- if (false)
- Log.v(TAG, "fileToDelete is " + fileToDelete);
- try {
- (new File(fileToDelete)).delete();
- } catch (SecurityException ex) {
- }
- }
-
- Log.v(TAG, "/pruneDeadThumbnailFiles... " + c);
- } catch (RemoteException e) {
- // We will soon be killed...
- } finally {
- if (c != null) {
- c.close();
- }
- }
- }
-
static class MediaBulkDeleter {
StringBuilder whereClause = new StringBuilder();
ArrayList whereArgs = new ArrayList(100);
@@ -1373,9 +1324,6 @@ public class MediaScanner implements AutoCloseable {
processPlayLists();
}
- if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external")))
- pruneDeadThumbnailFiles();
-
// allow GC to clean up
mPlayLists.clear();
}
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index 664308c45bf..98993676ce4 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -44,13 +44,14 @@ import java.util.Hashtable;
*/
public class MiniThumbFile {
private static final String TAG = "MiniThumbFile";
- private static final int MINI_THUMB_DATA_FILE_VERSION = 3;
+ private static final int MINI_THUMB_DATA_FILE_VERSION = 4;
public static final int BYTES_PER_MINTHUMB = 10000;
private static final int HEADER_SIZE = 1 + 8 + 4;
private Uri mUri;
private RandomAccessFile mMiniThumbFile;
private FileChannel mChannel;
private ByteBuffer mBuffer;
+ private ByteBuffer mEmptyBuffer;
private static final Hashtable sThumbFiles =
new Hashtable();
@@ -127,9 +128,10 @@ public class MiniThumbFile {
return mMiniThumbFile;
}
- public MiniThumbFile(Uri uri) {
+ private MiniThumbFile(Uri uri) {
mUri = uri;
mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
+ mEmptyBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
}
public synchronized void deactivate() {
@@ -184,6 +186,54 @@ public class MiniThumbFile {
return 0;
}
+ public synchronized void eraseMiniThumb(long id) {
+ RandomAccessFile r = miniThumbDataFile();
+ if (r != null) {
+ long pos = id * BYTES_PER_MINTHUMB;
+ FileLock lock = null;
+ try {
+ mBuffer.clear();
+ mBuffer.limit(1 + 8);
+
+ lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false);
+ // check that we can read the following 9 bytes
+ // (1 for the "status" and 8 for the long)
+ if (mChannel.read(mBuffer, pos) == 9) {
+ mBuffer.position(0);
+ if (mBuffer.get() == 1) {
+ long currentMagic = mBuffer.getLong();
+ if (currentMagic == 0) {
+ // there is no thumbnail stored here
+ Log.i(TAG, "no thumbnail for id " + id);
+ return;
+ }
+ // zero out the thumbnail slot
+ // Log.v(TAG, "clearing slot " + id + ", magic " + currentMagic
+ // + " at offset " + pos);
+ mChannel.write(mEmptyBuffer, pos);
+ }
+ } else {
+ // Log.v(TAG, "No slot");
+ }
+ } catch (IOException ex) {
+ Log.v(TAG, "Got exception checking file magic: ", ex);
+ } catch (RuntimeException ex) {
+ // Other NIO related exception like disk full, read only channel..etc
+ Log.e(TAG, "Got exception when reading magic, id = " + id +
+ ", disk full or mount read-only? " + ex.getClass());
+ } finally {
+ try {
+ if (lock != null) lock.release();
+ }
+ catch (IOException ex) {
+ // ignore it.
+ }
+ }
+ } else {
+ // Log.v(TAG, "No data file");
+ }
+ }
+
public synchronized void saveMiniThumbToFile(byte[] data, long id, long magic)
throws IOException {
RandomAccessFile r = miniThumbDataFile();
--
GitLab
From 48c570b09f23457e6805a2a4bee86c31685442b2 Mon Sep 17 00:00:00 2001
From: Tyler Gunn
Date: Fri, 9 Mar 2018 02:33:22 +0000
Subject: [PATCH 035/488] Support enhanced call blocking function
- Add new carrier config to determine whether to enable
enhanced call blocking feature.
- Add new I/F to get/set the call blocking enabled status.
- Add new API to support checking whether a number is
block number with specific extras.
Bug: 28189985
Test: Manual
Merged-In: Ic89223cd31a4a8f3552360565b772315ec271902
Change-Id: Ic89223cd31a4a8f3552360565b772315ec271902
(cherry picked from commit 72e05c03820e1d0504a3987e868bfab5ac0855bc)
---
.../provider/BlockedNumberContract.java | 116 ++++++++++++++++--
.../telephony/CarrierConfigManager.java | 30 ++++-
2 files changed, 136 insertions(+), 10 deletions(-)
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index fb11d00cec4..8aef012daa4 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -228,6 +228,25 @@ public class BlockedNumberContract {
/** @hide */
public static final String RES_CAN_BLOCK_NUMBERS = "can_block";
+ /** @hide */
+ public static final String RES_ENHANCED_SETTING_IS_ENABLED = "enhanced_setting_enabled";
+
+ /** @hide */
+ public static final String RES_SHOW_EMERGENCY_CALL_NOTIFICATION =
+ "show_emergency_call_notification";
+
+ /** @hide */
+ public static final String EXTRA_ENHANCED_SETTING_KEY = "extra_enhanced_setting_key";
+
+ /** @hide */
+ public static final String EXTRA_ENHANCED_SETTING_VALUE = "extra_enhanced_setting_value";
+
+ /** @hide */
+ public static final String EXTRA_CONTACT_EXIST = "extra_contact_exist";
+
+ /** @hide */
+ public static final String EXTRA_CALL_PRESENTATION = "extra_call_presentation";
+
/**
* Returns whether a given number is in the blocked list.
*
@@ -314,11 +333,33 @@ public class BlockedNumberContract {
public static final String METHOD_GET_BLOCK_SUPPRESSION_STATUS =
"get_block_suppression_status";
+ public static final String METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION =
+ "should_show_emergency_call_notification";
+
public static final String RES_IS_BLOCKING_SUPPRESSED = "blocking_suppressed";
public static final String RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP =
"blocking_suppressed_until_timestamp";
+ public static final String METHOD_GET_ENHANCED_BLOCK_SETTING = "get_enhanced_block_setting";
+ public static final String METHOD_SET_ENHANCED_BLOCK_SETTING = "set_enhanced_block_setting";
+
+ /* Preference key of block numbers not in contacts setting. */
+ public static final String ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED =
+ "block_numbers_not_in_contacts_setting";
+ /* Preference key of block private number calls setting. */
+ public static final String ENHANCED_SETTING_KEY_BLOCK_PRIVATE =
+ "block_private_number_calls_setting";
+ /* Preference key of block payphone calls setting. */
+ public static final String ENHANCED_SETTING_KEY_BLOCK_PAYPHONE =
+ "block_payphone_calls_setting";
+ /* Preference key of block unknown calls setting. */
+ public static final String ENHANCED_SETTING_KEY_BLOCK_UNKNOWN =
+ "block_unknown_calls_setting";
+ /* Preference key for whether should show an emergency call notification. */
+ public static final String ENHANCED_SETTING_KEY_SHOW_EMERGENCY_CALL_NOTIFICATION =
+ "show_emergency_call_notification";
+
/**
* Notifies the provider that emergency services were contacted by the user.
*
This results in {@link #shouldSystemBlockNumber} returning {@code false} independent
@@ -342,13 +383,19 @@ public class BlockedNumberContract {
/**
* Returns {@code true} if {@code phoneNumber} is blocked taking
- * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services have
- * not been contacted recently, this method is equivalent to
- * {@link #isBlocked(Context, String)}.
+ * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services
+ * have not been contacted recently and enhanced call blocking not been enabled, this
+ * method is equivalent to {@link #isBlocked(Context, String)}.
+ *
+ * @param context the context of the caller.
+ * @param phoneNumber the number to check.
+ * @param extras the extra attribute of the number.
+ * @return {@code true} if should block the number. {@code false} otherwise.
*/
- public static boolean shouldSystemBlockNumber(Context context, String phoneNumber) {
+ public static boolean shouldSystemBlockNumber(Context context, String phoneNumber,
+ Bundle extras) {
final Bundle res = context.getContentResolver().call(
- AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, null);
+ AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, extras);
return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
}
@@ -363,9 +410,62 @@ public class BlockedNumberContract {
}
/**
- * Represents the current status of {@link #shouldSystemBlockNumber(Context, String)}. If
- * emergency services have been contacted recently, {@link #isSuppressed} is {@code true},
- * and blocking is disabled until the timestamp {@link #untilTimestampMillis}.
+ * Check whether should show the emergency call notification.
+ *
+ * @param context the context of the caller.
+ * @return {@code true} if should show emergency call notification. {@code false} otherwise.
+ */
+ public static boolean shouldShowEmergencyCallNotification(Context context) {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION, null, null);
+ return res != null && res.getBoolean(RES_SHOW_EMERGENCY_CALL_NOTIFICATION, false);
+ }
+
+ /**
+ * Check whether the enhanced block setting is enabled.
+ *
+ * @param context the context of the caller.
+ * @param key the key of the setting to check, can be
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED}
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_PRIVATE}
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_PAYPHONE}
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_UNKNOWN}
+ * {@link #ENHANCED_SETTING_KEY_EMERGENCY_CALL_NOTIFICATION_SHOWING}
+ * @return {@code true} if the setting is enabled. {@code false} otherwise.
+ */
+ public static boolean getEnhancedBlockSetting(Context context, String key) {
+ Bundle extras = new Bundle();
+ extras.putString(EXTRA_ENHANCED_SETTING_KEY, key);
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_GET_ENHANCED_BLOCK_SETTING, null, extras);
+ return res != null && res.getBoolean(RES_ENHANCED_SETTING_IS_ENABLED, false);
+ }
+
+ /**
+ * Set the enhanced block setting enabled status.
+ *
+ * @param context the context of the caller.
+ * @param key the key of the setting to set, can be
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED}
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_PRIVATE}
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_PAYPHONE}
+ * {@link #ENHANCED_SETTING_KEY_BLOCK_UNKNOWN}
+ * {@link #ENHANCED_SETTING_KEY_EMERGENCY_CALL_NOTIFICATION_SHOWING}
+ * @param value the enabled statue of the setting to set.
+ */
+ public static void setEnhancedBlockSetting(Context context, String key, boolean value) {
+ Bundle extras = new Bundle();
+ extras.putString(EXTRA_ENHANCED_SETTING_KEY, key);
+ extras.putBoolean(EXTRA_ENHANCED_SETTING_VALUE, value);
+ context.getContentResolver().call(AUTHORITY_URI, METHOD_SET_ENHANCED_BLOCK_SETTING,
+ null, extras);
+ }
+
+ /**
+ * Represents the current status of
+ * {@link #shouldSystemBlockNumber(Context, String, Bundle)}. If emergency services
+ * have been contacted recently, {@link #isSuppressed} is {@code true}, and blocking
+ * is disabled until the timestamp {@link #untilTimestampMillis}.
*/
public static class BlockSuppressionStatus {
public final boolean isSuppressed;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d43db324631..eebe2a196c6 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1285,12 +1285,37 @@ public class CarrierConfigManager {
/**
* The duration in seconds that platform call and message blocking is disabled after the user
- * contacts emergency services. Platform considers values in the range 0 to 604800 (one week) as
- * valid. See {@link android.provider.BlockedNumberContract#isBlocked(Context, String)}).
+ * contacts emergency services. Platform considers values for below cases:
+ * 1) 0 <= VALUE <= 604800(one week): the value will be used as the duration directly.
+ * 2) VALUE > 604800(one week): will use the default value as duration instead.
+ * 3) VALUE < 0: block will be disabled forever until user re-eanble block manually,
+ * the suggested value to disable forever is -1.
+ * See {@code android.provider.BlockedNumberContract#notifyEmergencyContact(Context)}
+ * See {@code android.provider.BlockedNumberContract#isBlocked(Context, String)}.
*/
public static final String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT =
"duration_blocking_disabled_after_emergency_int";
+ /**
+ * Determines whether to enable enhanced call blocking feature on the device.
+ * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED
+ * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE
+ * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE
+ * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN
+ *
+ *
+ * 1. For Single SIM(SS) device, it can be customized in both carrier_config_mccmnc.xml
+ * and vendor.xml.
+ *
+ * 2. For Dual SIM(DS) device, it should be customized in vendor.xml, since call blocking
+ * function is used regardless of SIM.
+ *
+ * If {@code true} enable enhanced call blocking feature on the device, {@code false} otherwise.
+ * @hide
+ */
+ public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL =
+ "support_enhanced_call_blocking_bool";
+
/**
* For carriers which require an empty flash to be sent before sending the normal 3-way calling
* flash, the duration in milliseconds of the empty flash to send. When {@code 0}, no empty
@@ -2052,6 +2077,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL, false);
sDefaults.putBoolean(KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL, false);
+ sDefaults.putBoolean(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL, false);
// MMS defaults
sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
--
GitLab
From 09da294c7a3fc65aa3d9b34bb332fa962fa04f4c Mon Sep 17 00:00:00 2001
From: Kevin Chyn
Date: Fri, 9 Mar 2018 13:13:11 -0800
Subject: [PATCH 036/488] Fingerprint should check current client when task
stack changes
Fixes: 74407323
Test: manual test with FingerprintDialog app, modified to not cancel
when onPause()
Change-Id: I039ca5e8ea510b7bc1a12711c2213bd22f1198b3
---
.../fingerprint/FingerprintService.java | 34 +++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index c3259c312cd..ac85484e7f7 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -26,8 +26,10 @@ import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.AlarmManager;
import android.app.AppOpsManager;
+import android.app.IActivityManager;
import android.app.PendingIntent;
import android.app.SynchronousUserSwitchObserver;
+import android.app.TaskStackListener;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -137,6 +139,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
@GuardedBy("this")
private IBiometricsFingerprint mDaemon;
private IStatusBarService mStatusBarService;
+ private final IActivityManager mActivityManager;
private final PowerManager mPowerManager;
private final AlarmManager mAlarmManager;
private final UserManager mUserManager;
@@ -215,6 +218,30 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
}
};
+ private final TaskStackListener mTaskStackListener = new TaskStackListener() {
+ @Override
+ public void onTaskStackChanged() {
+ try {
+ if (!(mCurrentClient instanceof AuthenticationClient)) {
+ return;
+ }
+ if (isKeyguard(mCurrentClient.getOwnerString())) {
+ return; // Keyguard is always allowed
+ }
+ List runningTasks = mActivityManager.getTasks(1);
+ if (!runningTasks.isEmpty()) {
+ if (runningTasks.get(0).topActivity.getPackageName()
+ != mCurrentClient.getOwnerString()) {
+ mCurrentClient.stop(false /* initiatedByClient */);
+ Slog.e(TAG, "Stopping background authentication");
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to get running tasks", e);
+ }
+ }
+ };
+
public FingerprintService(Context context) {
super(context);
mContext = context;
@@ -230,6 +257,13 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
mFailedAttempts = new SparseIntArray();
mStatusBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ mActivityManager = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE))
+ .getService();
+ try {
+ mActivityManager.registerTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not register task stack listener", e);
+ }
}
@Override
--
GitLab
From 2c1a1779027d2ed4c6d34654ef4026f3f3198d55 Mon Sep 17 00:00:00 2001
From: Eric Schwarzenbach
Date: Fri, 2 Mar 2018 17:47:13 -0800
Subject: [PATCH 037/488] Add Duplex mode to ServiceState.
Adds getChannelNumber() to CellIdentity.
Creates a static utility class to calculate the duplex mode from an
EARFCN.
Bug: 73728783
Test: runtest frameworks-telephony
Change-Id: I5b5c4efa7e17594ce9397cf65e129147affe96bd
Merged-In: I5b5c4efa7e17594ce9397cf65e129147affe96bd
(cherry picked from commit a483ce3bfd2df3b0c88382d59e67bb2bfcd361d8)
---
.../android/telephony/AccessNetworkUtils.java | 167 ++++++++++++++++++
.../java/android/telephony/CellIdentity.java | 13 ++
.../android/telephony/CellIdentityGsm.java | 5 +
.../android/telephony/CellIdentityLte.java | 6 +
.../android/telephony/CellIdentityWcdma.java | 6 +
.../java/android/telephony/ServiceState.java | 11 +-
6 files changed, 205 insertions(+), 3 deletions(-)
create mode 100644 telephony/java/android/telephony/AccessNetworkUtils.java
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
new file mode 100644
index 00000000000..5d2c225f28e
--- /dev/null
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -0,0 +1,167 @@
+package android.telephony;
+
+import static android.telephony.ServiceState.DUPLEX_MODE_FDD;
+import static android.telephony.ServiceState.DUPLEX_MODE_TDD;
+import static android.telephony.ServiceState.DUPLEX_MODE_UNKNOWN;
+
+import android.telephony.AccessNetworkConstants.EutranBand;
+import android.telephony.ServiceState.DuplexMode;
+
+
+/**
+ * Utilities to map between radio constants.
+ *
+ * @hide
+ */
+public class AccessNetworkUtils {
+
+ // do not instantiate
+ private AccessNetworkUtils() {}
+
+ public static final int INVALID_BAND = -1;
+
+ /**
+ * Gets the duplex mode for the given EUTRAN operating band.
+ *
+ *
See 3GPP 36.101 sec 5.5-1 for calculation
+ *
+ * @param band The EUTRAN band number
+ * @return The duplex mode of the given EUTRAN band
+ */
+ @DuplexMode
+ public static int getDuplexModeForEutranBand(int band) {
+ if (band == INVALID_BAND) {
+ return DUPLEX_MODE_UNKNOWN;
+ }
+
+ if (band >= EutranBand.BAND_68) {
+ return DUPLEX_MODE_UNKNOWN;
+ } else if (band >= EutranBand.BAND_65) {
+ return DUPLEX_MODE_FDD;
+ } else if (band >= EutranBand.BAND_47) {
+ return DUPLEX_MODE_UNKNOWN;
+ } else if (band >= EutranBand.BAND_33) {
+ return DUPLEX_MODE_TDD;
+ } else if (band >= EutranBand.BAND_1) {
+ return DUPLEX_MODE_FDD;
+ }
+
+ return DUPLEX_MODE_UNKNOWN;
+ }
+
+ /**
+ * Gets the EUTRAN Operating band for a given downlink EARFCN.
+ *
+ *
See 3GPP 36.101 sec 5.7.3-1 for calculation.
+ *
+ * @param earfcn The downlink EARFCN
+ * @return Operating band number, or {@link #INVALID_BAND} if no corresponding band exists
+ */
+ public static int getOperatingBandForEarfcn(int earfcn) {
+ if (earfcn > 67535) {
+ return INVALID_BAND;
+ } else if (earfcn >= 67366) {
+ return INVALID_BAND; // band 67 only for CarrierAgg
+ } else if (earfcn >= 66436) {
+ return EutranBand.BAND_66;
+ } else if (earfcn >= 65536) {
+ return EutranBand.BAND_65;
+ } else if (earfcn > 54339) {
+ return INVALID_BAND;
+ } else if (earfcn >= 46790 /* inferred from the end range of BAND_45 */) {
+ return EutranBand.BAND_46;
+ } else if (earfcn >= 46590) {
+ return EutranBand.BAND_45;
+ } else if (earfcn >= 45590) {
+ return EutranBand.BAND_44;
+ } else if (earfcn >= 43590) {
+ return EutranBand.BAND_43;
+ } else if (earfcn >= 41590) {
+ return EutranBand.BAND_42;
+ } else if (earfcn >= 39650) {
+ return EutranBand.BAND_41;
+ } else if (earfcn >= 38650) {
+ return EutranBand.BAND_40;
+ } else if (earfcn >= 38250) {
+ return EutranBand.BAND_39;
+ } else if (earfcn >= 37750) {
+ return EutranBand.BAND_38;
+ } else if (earfcn >= 37550) {
+ return EutranBand.BAND_37;
+ } else if (earfcn >= 36950) {
+ return EutranBand.BAND_36;
+ } else if (earfcn >= 36350) {
+ return EutranBand.BAND_35;
+ } else if (earfcn >= 36200) {
+ return EutranBand.BAND_34;
+ } else if (earfcn >= 36000) {
+ return EutranBand.BAND_33;
+ } else if (earfcn > 10359) {
+ return INVALID_BAND;
+ } else if (earfcn >= 9920) {
+ return INVALID_BAND; // band 32 only for CarrierAgg
+ } else if (earfcn >= 9870) {
+ return EutranBand.BAND_31;
+ } else if (earfcn >= 9770) {
+ return EutranBand.BAND_30;
+ } else if (earfcn >= 9660) {
+ return INVALID_BAND; // band 29 only for CarrierAgg
+ } else if (earfcn >= 9210) {
+ return EutranBand.BAND_28;
+ } else if (earfcn >= 9040) {
+ return EutranBand.BAND_27;
+ } else if (earfcn >= 8690) {
+ return EutranBand.BAND_26;
+ } else if (earfcn >= 8040) {
+ return EutranBand.BAND_25;
+ } else if (earfcn >= 7700) {
+ return EutranBand.BAND_24;
+ } else if (earfcn >= 7500) {
+ return EutranBand.BAND_23;
+ } else if (earfcn >= 6600) {
+ return EutranBand.BAND_22;
+ } else if (earfcn >= 6450) {
+ return EutranBand.BAND_21;
+ } else if (earfcn >= 6150) {
+ return EutranBand.BAND_20;
+ } else if (earfcn >= 6000) {
+ return EutranBand.BAND_19;
+ } else if (earfcn >= 5850) {
+ return EutranBand.BAND_18;
+ } else if (earfcn >= 5730) {
+ return EutranBand.BAND_17;
+ } else if (earfcn > 5379) {
+ return INVALID_BAND;
+ } else if (earfcn >= 5280) {
+ return EutranBand.BAND_14;
+ } else if (earfcn >= 5180) {
+ return EutranBand.BAND_13;
+ } else if (earfcn >= 5010) {
+ return EutranBand.BAND_12;
+ } else if (earfcn >= 4750) {
+ return EutranBand.BAND_11;
+ } else if (earfcn >= 4150) {
+ return EutranBand.BAND_10;
+ } else if (earfcn >= 3800) {
+ return EutranBand.BAND_9;
+ } else if (earfcn >= 3450) {
+ return EutranBand.BAND_8;
+ } else if (earfcn >= 2750) {
+ return EutranBand.BAND_7;
+ } else if (earfcn >= 2650) {
+ return EutranBand.BAND_6;
+ } else if (earfcn >= 2400) {
+ return EutranBand.BAND_5;
+ } else if (earfcn >= 1950) {
+ return EutranBand.BAND_4;
+ } else if (earfcn >= 1200) {
+ return EutranBand.BAND_3;
+ } else if (earfcn >= 600) {
+ return EutranBand.BAND_2;
+ } else if (earfcn >= 0) {
+ return EutranBand.BAND_1;
+ }
+
+ return INVALID_BAND;
+ }
+}
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index e092d52d91b..08f8bb6494a 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -68,6 +68,9 @@ public abstract class CellIdentity implements Parcelable {
*/
public static final int TYPE_TDSCDMA = 5;
+ /** @hide */
+ public static final int INVALID_CHANNEL_NUMBER = -1;
+
// Log tag
/** @hide */
protected final String mTag;
@@ -124,6 +127,16 @@ public abstract class CellIdentity implements Parcelable {
*/
public @Type int getType() { return mType; }
+ /**
+ * Returns the channel number of the cell identity.
+ *
+ * @hide
+ * @return The channel number, or {@link #INVALID_CHANNEL_NUMBER} if not implemented
+ */
+ public int getChannelNumber() {
+ return INVALID_CHANNEL_NUMBER;
+ }
+
/**
* Used by child classes for parceling.
*
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index d35eb60916f..52944a8ac26 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -203,6 +203,11 @@ public final class CellIdentityGsm extends CellIdentity {
return mAlphaShort;
}
+ /** @hide */
+ @Override
+ public int getChannelNumber() {
+ return mArfcn;
+ }
/**
* @deprecated Primary Scrambling Code is not applicable to GSM.
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 2b8eb5f3cca..37fb07521b0 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -213,6 +213,12 @@ public final class CellIdentityLte extends CellIdentity {
return mAlphaShort;
}
+ /** @hide */
+ @Override
+ public int getChannelNumber() {
+ return mEarfcn;
+ }
+
@Override
public int hashCode() {
return Objects.hash(mMccStr, mMncStr, mCi, mPci, mTac, mAlphaLong, mAlphaShort);
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index a5fd7dd9794..affa0c15862 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -206,6 +206,12 @@ public final class CellIdentityWcdma extends CellIdentity {
return mUarfcn;
}
+ /** @hide */
+ @Override
+ public int getChannelNumber() {
+ return mUarfcn;
+ }
+
@Override
public boolean equals(Object other) {
if (this == other) {
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 82a7450945f..a9c1cf6c7bc 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -471,9 +471,13 @@ public class ServiceState implements Parcelable {
*/
@DuplexMode
public int getDuplexMode() {
- // TODO(b/72117602) determine duplex mode from channel number, using 3GPP 36.101 sections
- // 5.7.3-1 and 5.5-1
- return DUPLEX_MODE_UNKNOWN;
+ // only support LTE duplex mode
+ if (!isLte(mRilDataRadioTechnology)) {
+ return DUPLEX_MODE_UNKNOWN;
+ }
+
+ int band = AccessNetworkUtils.getOperatingBandForEarfcn(mChannelNumber);
+ return AccessNetworkUtils.getDuplexModeForEutranBand(band);
}
/**
@@ -891,6 +895,7 @@ public class ServiceState implements Parcelable {
.append(", mDataRegState=").append(mDataRegState)
.append("(" + rilServiceStateToString(mDataRegState) + ")")
.append(", mChannelNumber=").append(mChannelNumber)
+ .append(", duplexMode()=").append(getDuplexMode())
.append(", mCellBandwidths=").append(Arrays.toString(mCellBandwidths))
.append(", mVoiceRoamingType=").append(getRoamingLogString(mVoiceRoamingType))
.append(", mDataRoamingType=").append(getRoamingLogString(mDataRoamingType))
--
GitLab
From f3e412e5021c43491ed3ced61f02c2fd436e064e Mon Sep 17 00:00:00 2001
From: Winson Chung
Date: Thu, 8 Mar 2018 11:07:40 -0800
Subject: [PATCH 038/488] Expose whether a snapshot is a real snapshot
- This allows launcher to distinguish between a real snapshot and an app
theme snapshot, which it will decorate differently.
Bug: 72809891
Test: atest com.android.server.wm.TaskSnapshotPersisterLoaderTest
Change-Id: Ia94591ab83ef312556f138cf11398cc5680ad798
---
core/java/android/app/ActivityManager.java | 17 +++++++++++++++--
.../shared/recents/model/ThumbnailData.java | 3 +++
proto/src/task_snapshot.proto | 1 +
.../server/wm/TaskSnapshotController.java | 6 ++++--
.../android/server/wm/TaskSnapshotLoader.java | 3 ++-
.../server/wm/TaskSnapshotPersister.java | 1 +
.../wm/TaskSnapshotPersisterLoaderTest.java | 19 ++++++++++++++++++-
.../wm/TaskSnapshotPersisterTestBase.java | 6 +++++-
.../server/wm/TaskSnapshotSurfaceTest.java | 2 +-
9 files changed, 50 insertions(+), 8 deletions(-)
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2d73ce0c059..a18ba718ece 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2101,15 +2101,17 @@ public class ActivityManager {
private final int mOrientation;
private final Rect mContentInsets;
private final boolean mReducedResolution;
+ private final boolean mIsRealSnapshot;
private final float mScale;
public TaskSnapshot(GraphicBuffer snapshot, int orientation, Rect contentInsets,
- boolean reducedResolution, float scale) {
+ boolean reducedResolution, float scale, boolean isRealSnapshot) {
mSnapshot = snapshot;
mOrientation = orientation;
mContentInsets = new Rect(contentInsets);
mReducedResolution = reducedResolution;
mScale = scale;
+ mIsRealSnapshot = isRealSnapshot;
}
private TaskSnapshot(Parcel source) {
@@ -2118,6 +2120,7 @@ public class ActivityManager {
mContentInsets = source.readParcelable(null /* classLoader */);
mReducedResolution = source.readBoolean();
mScale = source.readFloat();
+ mIsRealSnapshot = source.readBoolean();
}
/**
@@ -2149,6 +2152,14 @@ public class ActivityManager {
return mReducedResolution;
}
+ /**
+ * @return Whether or not the snapshot is a real snapshot or an app-theme generated snapshot
+ * due to the task having a secure window or having previews disabled.
+ */
+ public boolean isRealSnapshot() {
+ return mIsRealSnapshot;
+ }
+
/**
* @return The scale this snapshot was taken in.
*/
@@ -2168,13 +2179,15 @@ public class ActivityManager {
dest.writeParcelable(mContentInsets, 0);
dest.writeBoolean(mReducedResolution);
dest.writeFloat(mScale);
+ dest.writeBoolean(mIsRealSnapshot);
}
@Override
public String toString() {
return "TaskSnapshot{mSnapshot=" + mSnapshot + " mOrientation=" + mOrientation
+ " mContentInsets=" + mContentInsets.toShortString()
- + " mReducedResolution=" + mReducedResolution + " mScale=" + mScale;
+ + " mReducedResolution=" + mReducedResolution + " mScale=" + mScale
+ + " mIsRealSnapshot=" + mIsRealSnapshot;
}
public static final Creator CREATOR = new Creator() {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index dd1763bb118..924e85dec37 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -31,6 +31,7 @@ public class ThumbnailData {
public int orientation;
public Rect insets;
public boolean reducedResolution;
+ public boolean isRealSnapshot;
public float scale;
public ThumbnailData() {
@@ -39,6 +40,7 @@ public class ThumbnailData {
insets = new Rect();
reducedResolution = false;
scale = 1f;
+ isRealSnapshot = true;
}
public ThumbnailData(TaskSnapshot snapshot) {
@@ -47,5 +49,6 @@ public class ThumbnailData {
orientation = snapshot.getOrientation();
reducedResolution = snapshot.isReducedResolution();
scale = snapshot.getScale();
+ isRealSnapshot = snapshot.isRealSnapshot();
}
}
diff --git a/proto/src/task_snapshot.proto b/proto/src/task_snapshot.proto
index c9d5c272d48..490a59e770e 100644
--- a/proto/src/task_snapshot.proto
+++ b/proto/src/task_snapshot.proto
@@ -27,4 +27,5 @@
int32 inset_top = 3;
int32 inset_right = 4;
int32 inset_bottom = 5;
+ bool is_real_snapshot = 6;
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index a5a1ca5a9ff..9310dc488c7 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -273,7 +273,8 @@ class TaskSnapshotController {
}
return new TaskSnapshot(buffer, top.getConfiguration().orientation,
getInsetsFromTaskBounds(mainWindow, task),
- isLowRamDevice /* reduced */, scaleFraction /* scale */);
+ isLowRamDevice /* reduced */, scaleFraction /* scale */,
+ true /* isRealSnapshot */);
}
private boolean shouldDisableSnapshots() {
@@ -369,7 +370,8 @@ class TaskSnapshotController {
}
return new TaskSnapshot(hwBitmap.createGraphicBufferHandle(),
topChild.getConfiguration().orientation, mainWindow.mStableInsets,
- ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */);
+ ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */,
+ false /* isRealSnapshot */);
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
index 537f3177595..31da5f3ff1c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
@@ -89,7 +89,8 @@ class TaskSnapshotLoader {
}
return new TaskSnapshot(buffer, proto.orientation,
new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom),
- reducedResolution, reducedResolution ? REDUCED_SCALE : 1f);
+ reducedResolution, reducedResolution ? REDUCED_SCALE : 1f,
+ proto.isRealSnapshot);
} catch (IOException e) {
Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId);
return null;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 621bee7d17e..086fffa9d62 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -318,6 +318,7 @@ class TaskSnapshotPersister {
proto.insetTop = mSnapshot.getContentInsets().top;
proto.insetRight = mSnapshot.getContentInsets().right;
proto.insetBottom = mSnapshot.getContentInsets().bottom;
+ proto.isRealSnapshot = mSnapshot.isRealSnapshot();
final byte[] bytes = TaskSnapshotProto.toByteArray(proto);
final File file = getProtoFile(mTaskId, mUserId);
final AtomicFile atomicFile = new AtomicFile(file);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index 96fbc140229..80cbf2aae3f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -42,7 +42,7 @@ import java.io.File;
/**
* Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader}
*
- * runtest frameworks-services -c com.android.server.wm.TaskSnapshotPersisterLoaderTest
+ * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest
*/
@MediumTest
@Presubmit
@@ -162,6 +162,23 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa
assertNull(snapshotNotExist);
}
+ @Test
+ public void testIsRealSnapshotPersistAndLoadSnapshot() {
+ TaskSnapshot a = createSnapshot(1f /* scale */, true /* isRealSnapshot */);
+ TaskSnapshot b = createSnapshot(1f /* scale */, false /* isRealSnapshot */);
+ assertTrue(a.isRealSnapshot());
+ assertFalse(b.isRealSnapshot());
+ mPersister.persistSnapshot(1, mTestUserId, a);
+ mPersister.persistSnapshot(2, mTestUserId, b);
+ mPersister.waitForQueueEmpty();
+ final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */);
+ final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
+ assertNotNull(snapshotA);
+ assertNotNull(snapshotB);
+ assertTrue(snapshotA.isRealSnapshot());
+ assertFalse(snapshotB.isRealSnapshot());
+ }
+
@Test
public void testRemoveObsoleteFiles() {
mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index b49a0fdf8f3..2ad5bf40405 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -84,12 +84,16 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase {
}
TaskSnapshot createSnapshot(float scale) {
+ return createSnapshot(scale, true /* isRealSnapshot */);
+ }
+
+ TaskSnapshot createSnapshot(float scale, boolean isRealSnapshot) {
final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888,
USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY);
Canvas c = buffer.lockCanvas();
c.drawColor(Color.RED);
buffer.unlockCanvasAndPost(c);
return new TaskSnapshot(buffer, ORIENTATION_PORTRAIT, TEST_INSETS,
- scale < 1f /* reducedResolution */, scale);
+ scale < 1f /* reducedResolution */, scale, isRealSnapshot);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 4288eac0faa..d5334babc1a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -60,7 +60,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888,
GraphicBuffer.USAGE_SW_READ_NEVER | GraphicBuffer.USAGE_SW_WRITE_NEVER);
final TaskSnapshot snapshot = new TaskSnapshot(buffer,
- ORIENTATION_PORTRAIT, contentInsets, false, 1.0f);
+ ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */);
mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test",
Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds,
ORIENTATION_PORTRAIT);
--
GitLab
From 2c23b130114c92c9bc52c3b4ba085ebaa85da832 Mon Sep 17 00:00:00 2001
From: Rohan Shah
Date: Fri, 9 Mar 2018 13:41:11 -0800
Subject: [PATCH 039/488] [QS] Update hotspot tile secondary text (data saver)
Updating the secondary text to show a different message when data saver
is enabled (to explain to the user why they can't toggle the tile).
Also collapsed double ternary to make it a bit easier to read.
Test: Visually
Bug: 33003328
Change-Id: I8a98f95c60ec9dcbe5899e87e29759e8d377b106
---
packages/SystemUI/res/values/strings.xml | 3 +++
.../systemui/qs/tiles/HotspotTile.java | 24 ++++++++++++-------
2 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 89e6da38ffa..4eb122c5545 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -780,6 +780,9 @@
HotspotTurning on…
+
+ Data Saver is on%d device
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 81e3d5ad17d..00d6bd0d307 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -137,7 +137,6 @@ public class HotspotTile extends QSTileImpl {
state.icon = mEnabledStatic;
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
- state.secondaryLabel = getSecondaryLabel(state.value, isTransient, numConnectedDevices);
state.isAirplaneMode = mAirplaneMode.getValue() != 0;
state.isTransient = isTransient;
state.slash.isSlashed = !state.value && !state.isTransient;
@@ -149,19 +148,26 @@ public class HotspotTile extends QSTileImpl {
final boolean isTileUnavailable = (state.isAirplaneMode || isDataSaverEnabled);
final boolean isTileActive = (state.value || state.isTransient);
- state.state = isTileUnavailable
- ? Tile.STATE_UNAVAILABLE
- : isTileActive
- ? Tile.STATE_ACTIVE
- : Tile.STATE_INACTIVE;
+
+ if (isTileUnavailable) {
+ state.state = Tile.STATE_UNAVAILABLE;
+ } else {
+ state.state = isTileActive ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ }
+
+ state.secondaryLabel = getSecondaryLabel(
+ isTileActive, isTransient, isDataSaverEnabled, numConnectedDevices);
}
@Nullable
- private String getSecondaryLabel(
- boolean enabled, boolean isTransient, int numConnectedDevices) {
+ private String getSecondaryLabel(boolean isActive, boolean isTransient,
+ boolean isDataSaverEnabled, int numConnectedDevices) {
if (isTransient) {
return mContext.getString(R.string.quick_settings_hotspot_secondary_label_transient);
- } else if (numConnectedDevices > 0 && enabled) {
+ } else if (isDataSaverEnabled) {
+ return mContext.getString(
+ R.string.quick_settings_hotspot_secondary_label_data_saver_enabled);
+ } else if (numConnectedDevices > 0 && isActive) {
return mContext.getResources().getQuantityString(
R.plurals.quick_settings_hotspot_secondary_label_num_devices,
numConnectedDevices,
--
GitLab
From 853cd8f6d259d6fc08daf8e509a9bc1e7c6682fa Mon Sep 17 00:00:00 2001
From: Rohan Shah
Date: Fri, 9 Mar 2018 15:14:59 -0800
Subject: [PATCH 040/488] Nit cleanup: Update TileLayout.onLayout
Made it a little easier to read onLayout/onMeasure. Separating this from
landscape CL just to keep a minor cleanup separate.
Bug: 73808887
Test: Visually
Change-Id: I817d6c92cda37ee0d99cd20ace06959a3bdc608d
---
.../com/android/systemui/qs/TileLayout.java | 26 ++++++++++++-------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 66823ca135c..1cb89c472db 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -92,9 +92,10 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int numTiles = mRecords.size();
final int width = MeasureSpec.getSize(widthMeasureSpec);
- final int rows = (numTiles + mColumns - 1) / mColumns;
+ final int numRows = (numTiles + mColumns - 1) / mColumns;
mCellWidth = (width - (mCellMarginHorizontal * (mColumns + 1))) / mColumns;
+ // Measure each QS tile.
View previousView = this;
for (TileRecord record : mRecords) {
if (record.tileView.getVisibility() == GONE) continue;
@@ -104,9 +105,10 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
// Only include the top margin in our measurement if we have more than 1 row to show.
// Otherwise, don't add the extra margin buffer at top.
- int height = (mCellHeight + mCellMarginVertical) * rows +
- (rows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0);
+ int height = (mCellHeight + mCellMarginVertical) * numRows +
+ (numRows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0);
if (height < 0) height = 0;
+
setMeasuredDimension(width, height);
}
@@ -122,24 +124,30 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int w = getWidth();
- boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
int row = 0;
int column = 0;
+
+ // Layout each QS tile.
for (int i = 0; i < mRecords.size(); i++, column++) {
+ // If we reached the last column available to layout a tile, wrap back to the next row.
if (column == mColumns) {
+ column = 0;
row++;
- column -= mColumns;
}
- TileRecord record = mRecords.get(i);
- int left = getColumnStart(column);
+
+ final TileRecord record = mRecords.get(i);
final int top = getRowTop(row);
- int right;
+ final int right;
+ final int left;
if (isRtl) {
- right = w - left;
+ right = w - getColumnStart(column);
left = right - mCellWidth;
} else {
+ left = getColumnStart(column);
right = left + mCellWidth;
}
+
record.tileView.layout(left, top, right, top + record.tileView.getMeasuredHeight());
}
}
--
GitLab
From a160ab18f8b573a01de37465dda0cee042984012 Mon Sep 17 00:00:00 2001
From: Rohan Shah
Date: Fri, 9 Mar 2018 15:47:36 -0800
Subject: [PATCH 041/488] [QS] Fix alarm text in QS header
Alarm text would go away until a restart. Turned out that we were
incorrectly making the view invisible immediately after animating it in
because the listener persisted on the ViewPropertyAnimator (single
instance per View).
Test: Visually using repro steps
Bug: 74359491
Change-Id: I2e0b8a9f4b767450df72f7ea7953f4ed75ae8f4c
---
.../com/android/systemui/qs/QuickStatusBarHeader.java | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index ec4d1a66f7c..4a0d7e25a22 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -31,6 +31,7 @@ import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -60,6 +61,8 @@ import java.util.Locale;
*/
public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue.Callbacks,
View.OnClickListener, NextAlarmController.NextAlarmChangeCallback {
+ private static final String TAG = "QuickStatusBarHeader";
+ private static final boolean DEBUG = false;
/** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */
private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6;
@@ -292,6 +295,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
@Override
public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
mNextAlarmText = nextAlarm != null ? formatNextAlarm(nextAlarm) : null;
+
if (mNextAlarmText != null) {
hideLongPressTooltip(true /* shouldFadeInAlarmText */);
} else {
@@ -351,6 +355,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (DEBUG) Log.d(TAG, "hideLongPressTooltip: Hid long press tip");
mLongPressTooltipView.setVisibility(View.INVISIBLE);
if (shouldShowAlarmText) {
@@ -361,7 +366,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
.start();
} else {
mLongPressTooltipView.setVisibility(View.INVISIBLE);
-
if (shouldShowAlarmText) {
showAlarmText();
}
@@ -377,9 +381,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
mNextAlarmView.setVisibility(View.VISIBLE);
mNextAlarmTextView.setText(mNextAlarmText);
+ // Animate the alarm back in. Make sure to clear the animator listener for the animation!
mNextAlarmView.animate()
.alpha(1f)
.setDuration(FADE_ANIMATION_DURATION_MS)
+ .setListener(null)
.start();
}
@@ -394,6 +400,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (DEBUG) Log.d(TAG, "hideAlarmText: Hid alarm text");
+
// Reset the alpha regardless of how the animation ends for the next
// time we show this view/want to animate it.
mNextAlarmView.setVisibility(View.INVISIBLE);
--
GitLab
From 54f51b0af3369647b02461fd31d71f026a179caa Mon Sep 17 00:00:00 2001
From: Christopher Tate
Date: Fri, 16 Feb 2018 11:07:12 -0800
Subject: [PATCH 042/488] Don't time out startForegroundService when debugging
the app
Change-Id: Ica022b028697335f60e5f52f6290b1f47ea0fb55
Fixes: 70870073
Test: manual
---
.../core/java/com/android/server/am/ActiveServices.java | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 26f83f560c5..eb4e32e4748 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3390,10 +3390,15 @@ public final class ActiveServices {
return;
}
+ app = r.app;
+ if (app != null && app.debugging) {
+ // The app's being debugged; let it ride
+ return;
+ }
+
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Service foreground-required timeout for " + r);
}
- app = r.app;
r.fgWaiting = false;
stopServiceLocked(r);
}
--
GitLab
From 53454a1c84815141734413b7d0e452b055ea5d28 Mon Sep 17 00:00:00 2001
From: Phil Weaver
Date: Fri, 9 Mar 2018 16:00:24 -0800
Subject: [PATCH 043/488] Don't let non-touchable windows retain a11y focus
Accessibility services can't see non-touchable windows,
so those windows should not be allowed to have
accessibility focus.
Bug: 70986605
Test: Manually went through bug steps, verified that
double-tapping on the screen has no effect.
Change-Id: I7be72331c5704f7aa99714a01bbb2e336eea15e1
---
.../accessibility/AccessibilityManagerService.java | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index b0b95868600..ecd47e8dd39 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3129,6 +3129,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
boolean activeWindowGone = true;
final int windowCount = windows.size();
+
+ // We'll clear accessibility focus if the window with focus is no longer visible to
+ // accessibility services
+ boolean shouldClearAccessibilityFocus =
+ mAccessibilityFocusedWindowId != INVALID_WINDOW_ID;
if (windowCount > 0) {
for (int i = 0; i < windowCount; i++) {
WindowInfo windowInfo = windows.get(i);
@@ -3166,6 +3171,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
if (window.getId() == mAccessibilityFocusedWindowId) {
window.setAccessibilityFocused(true);
+ shouldClearAccessibilityFocus = false;
}
}
}
@@ -3176,6 +3182,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
for (int i = oldWindowCount - 1; i >= 0; i--) {
oldWindowList.remove(i).recycle();
}
+
+ if (shouldClearAccessibilityFocus) {
+ clearAccessibilityFocus(mAccessibilityFocusedWindowId);
+ }
}
private void sendEventsForChangedWindowsLocked(List oldWindows,
--
GitLab
From bc9aac10e2a2c59fbea5a806f636c1bf7b6427c1 Mon Sep 17 00:00:00 2001
From: Lucas Dupin
Date: Sun, 4 Mar 2018 20:18:15 -0800
Subject: [PATCH 044/488] Bouncer animation
More obvious animation where bouncer position is influenced
by touches.
Test: Pull up bouncer, press back button
Test: Pull up bouncer, unlock with fp
Test: Unlock with fp with bouncer hidden
Test: Unlock with SmartLock
Test: Ask for auth on top of FLAG_SHOW_WHEN_LOCKED activity, press back
Test: packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
Fixes: 3699775
Change-Id: I016dfa17f17571261691669c82385d2d844c5917
---
.../dimens.xml | 5 +-
packages/SystemUI/res/values/dimens.xml | 4 +-
.../android/keyguard/KeyguardHostView.java | 1 -
.../systemui/classifier/AnglesClassifier.java | 4 +-
.../classifier/AnglesPercentageEvaluator.java | 7 ++-
.../classifier/AnglesVarianceEvaluator.java | 9 +--
.../systemui/classifier/Classifier.java | 1 +
.../classifier/DirectionEvaluator.java | 1 +
.../systemui/classifier/FalsingManager.java | 5 +-
.../keyguard/KeyguardViewMediator.java | 6 +-
.../statusbar/phone/KeyguardBouncer.java | 52 +++++++++++++++-
.../phone/KeyguardClockPositionAlgorithm.java | 60 ++++++++++++-------
.../phone/NotificationPanelView.java | 24 +++++---
.../systemui/statusbar/phone/PanelBar.java | 4 +-
.../systemui/statusbar/phone/PanelView.java | 28 +++++----
.../statusbar/phone/ScrimController.java | 22 ++-----
.../systemui/statusbar/phone/ScrimState.java | 25 +++++---
.../systemui/statusbar/phone/StatusBar.java | 5 +-
.../phone/StatusBarKeyguardViewManager.java | 31 +++++++++-
.../statusbar/phone/ScrimControllerTest.java | 14 ++++-
20 files changed, 218 insertions(+), 90 deletions(-)
rename packages/SystemUI/res/{values-h650dp => values-h800dp}/dimens.xml (75%)
diff --git a/packages/SystemUI/res/values-h650dp/dimens.xml b/packages/SystemUI/res/values-h800dp/dimens.xml
similarity index 75%
rename from packages/SystemUI/res/values-h650dp/dimens.xml
rename to packages/SystemUI/res/values-h800dp/dimens.xml
index 8a009530497..6a0e880675d 100644
--- a/packages/SystemUI/res/values-h650dp/dimens.xml
+++ b/packages/SystemUI/res/values-h800dp/dimens.xml
@@ -1,5 +1,5 @@
- 32dp
+
+ 76dp
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e12f7b7b1ef..0b65c70c7ef 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -443,8 +443,8 @@
30dp
-
- 26dp
+
+ 36dp250dp0.62
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
index 474fc90a1c3..62b50044132 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
@@ -149,7 +149,6 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
mSecurityContainer.setSecurityCallback(this);
mSecurityContainer.showPrimarySecurityScreen(false);
- // mSecurityContainer.updateSecurityViews(false /* not bouncing */);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
index 526e5fa78d3..e18ac74d446 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
@@ -79,8 +79,8 @@ public class AnglesClassifier extends StrokeClassifier {
@Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
Data data = mStrokeMap.get(stroke);
- return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance())
- + AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage());
+ return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance(), type)
+ + AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage(), type);
}
private static class Data {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
index e6c42da361c..e6e42f2d0ee 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
@@ -17,10 +17,11 @@
package com.android.systemui.classifier;
public class AnglesPercentageEvaluator {
- public static float evaluate(float value) {
+ public static float evaluate(float value, int type) {
+ final boolean secureUnlock = type == Classifier.BOUNCER_UNLOCK;
float evaluation = 0.0f;
- if (value < 1.00) evaluation++;
- if (value < 0.90) evaluation++;
+ if (value < 1.00 && !secureUnlock) evaluation++;
+ if (value < 0.90 && !secureUnlock) evaluation++;
if (value < 0.70) evaluation++;
return evaluation;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
index 99cc1a6d14f..6883dd0af3d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
@@ -17,14 +17,15 @@
package com.android.systemui.classifier;
public class AnglesVarianceEvaluator {
- public static float evaluate(float value) {
+ public static float evaluate(float value, int type) {
+ final boolean secureUnlock = type == Classifier.BOUNCER_UNLOCK;
float evaluation = 0.0f;
if (value > 0.05) evaluation++;
if (value > 0.10) evaluation++;
if (value > 0.20) evaluation++;
- if (value > 0.40) evaluation++;
- if (value > 0.80) evaluation++;
- if (value > 1.50) evaluation++;
+ if (value > 0.40 && !secureUnlock) evaluation++;
+ if (value > 0.80 && !secureUnlock) evaluation++;
+ if (value > 1.50 && !secureUnlock) evaluation++;
return evaluation;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
index cb761a9b131..909896eb6c5 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
@@ -31,6 +31,7 @@ public abstract class Classifier {
public static final int LEFT_AFFORDANCE = 5;
public static final int RIGHT_AFFORDANCE = 6;
public static final int GENERIC = 7;
+ public static final int BOUNCER_UNLOCK = 8;
/**
* Contains all the information about touch events from which the classifier can query
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
index e20b1ca6458..5f04222197a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
@@ -33,6 +33,7 @@ public class DirectionEvaluator {
}
break;
case Classifier.UNLOCK:
+ case Classifier.BOUNCER_UNLOCK:
if (!vertical || yDiff >= 0.0) {
return falsingEvaluation;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index ed659e2d16d..913e7819b7f 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -356,11 +356,12 @@ public class FalsingManager implements SensorEventListener {
mDataCollector.setQsExpanded(expanded);
}
- public void onTrackingStarted() {
+ public void onTrackingStarted(boolean secure) {
if (FalsingLog.ENABLED) {
FalsingLog.i("onTrackingStarted", "");
}
- mHumanInteractionClassifier.setType(Classifier.UNLOCK);
+ mHumanInteractionClassifier.setType(secure ?
+ Classifier.BOUNCER_UNLOCK : Classifier.UNLOCK);
mDataCollector.onTrackingStarted();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 694026473dc..a1b17e4ef0e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -83,6 +83,7 @@ import com.android.systemui.SystemUIFactory;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.phone.FingerprintUnlockController;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -2011,8 +2012,9 @@ public class KeyguardViewMediator extends SystemUI {
}
public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
- ViewGroup container, FingerprintUnlockController fingerprintUnlockController) {
- mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container,
+ ViewGroup container, NotificationPanelView panelView,
+ FingerprintUnlockController fingerprintUnlockController) {
+ mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container, panelView,
fingerprintUnlockController, mDismissCallbackRegistry);
return mStatusBarKeyguardViewManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index edfbd3f8ec7..11099550544 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.MathUtils;
import android.util.Slog;
import android.util.StatsLog;
import android.view.KeyEvent;
@@ -49,7 +50,8 @@ import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
*/
public class KeyguardBouncer {
- final static private String TAG = "KeyguardBouncer";
+ private static final String TAG = "KeyguardBouncer";
+ static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
protected final Context mContext;
protected final ViewMediatorCallback mCallback;
@@ -86,13 +88,25 @@ public class KeyguardBouncer {
}
public void show(boolean resetSecuritySelection) {
+ show(resetSecuritySelection, true /* notifyFalsing */);
+ }
+
+ public void show(boolean resetSecuritySelection, boolean notifyFalsing) {
final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
// In split system user mode, we never unlock system user.
return;
}
- mFalsingManager.onBouncerShown();
ensureView();
+
+ // On the keyguard, we want to show the bouncer when the user drags up, but it's
+ // not correct to end the falsing session. We still need to verify if those touches
+ // are valid.
+ // Later, at the end of the animation, when the bouncer is at the top of the screen,
+ // onFullyShown() will be called and FalsingManager will stop recording touches.
+ if (notifyFalsing) {
+ mFalsingManager.onBouncerShown();
+ }
if (resetSecuritySelection) {
// showPrimarySecurityScreen() updates the current security method. This is needed in
// case we are already showing and the current security method changed.
@@ -126,6 +140,28 @@ public class KeyguardBouncer {
mCallback.onBouncerVisiblityChanged(true /* shown */);
}
+ /**
+ * This method must be called at the end of the bouncer animation when
+ * the translation is performed manually by the user, otherwise FalsingManager
+ * will never be notified and its internal state will be out of sync.
+ */
+ public void onFullyShown() {
+ mFalsingManager.onBouncerShown();
+ }
+
+ /**
+ * This method must be called at the end of the bouncer animation when
+ * the translation is performed manually by the user, otherwise FalsingManager
+ * will never be notified and its internal state will be out of sync.
+ */
+ public void onFullyHidden() {
+ if (!mShowingSoon) {
+ cancelShowRunnable();
+ inflateView();
+ mFalsingManager.onBouncerHidden();
+ }
+ }
+
private final Runnable mShowRunnable = new Runnable() {
@Override
public void run() {
@@ -247,6 +283,18 @@ public class KeyguardBouncer {
mBouncerPromptReason = mCallback.getBouncerPromptReason();
}
+ /**
+ * Current notification panel expansion
+ * @param fraction 0 when notification panel is collapsed and 1 when expanded.
+ * @see StatusBarKeyguardViewManager#onPanelExpansionChanged
+ */
+ public void setExpansion(float fraction) {
+ if (mKeyguardView != null) {
+ mKeyguardView.setAlpha(MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction));
+ mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight());
+ }
+ }
+
protected void ensureView() {
// Removal of the view might be deferred to reduce unlock latency,
// in this case we need to force the removal, otherwise we'll
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 0cf26df7b37..1bd5e330318 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -79,14 +79,9 @@ public class KeyguardClockPositionAlgorithm {
private int mMaxShadeBottom;
/**
- * Margin that we should respect within the available space.
+ * Minimum distance from the status bar.
*/
- private int mContainerPadding;
-
- /**
- * Position where clock should be when the panel is collapsed.
- */
- private int mClockYTarget;
+ private int mContainerTopPadding;
/**
* @see NotificationPanelView#getMaxPanelHeight()
@@ -108,13 +103,23 @@ public class KeyguardClockPositionAlgorithm {
*/
private float mDarkAmount;
+ /**
+ * If keyguard will require a password or just fade away.
+ */
+ private boolean mCurrentlySecure;
+
+ /**
+ * If notification panel view currently has a touch.
+ */
+ private boolean mTracking;
+
/**
* Refreshes the dimension values.
*/
public void loadDimens(Resources res) {
mClockNotificationsMargin = res.getDimensionPixelSize(
R.dimen.keyguard_clock_notifications_margin);
- mContainerPadding = res.getDimensionPixelSize(
+ mContainerTopPadding = res.getDimensionPixelSize(
R.dimen.keyguard_clock_top_margin);
mBurnInPreventionOffsetX = res.getDimensionPixelSize(
R.dimen.burn_in_prevention_offset_x);
@@ -124,8 +129,8 @@ public class KeyguardClockPositionAlgorithm {
public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
float expandedHeight, float maxPanelHeight, int parentHeight, int keyguardStatusHeight,
- float dark) {
- mMinTopMargin = minTopMargin;
+ float dark, boolean secure, boolean tracking) {
+ mMinTopMargin = minTopMargin + mContainerTopPadding;
mMaxShadeBottom = maxShadeBottom;
mNotificationStackHeight = notificationStackHeight;
mExpandedHeight = expandedHeight;
@@ -133,13 +138,8 @@ public class KeyguardClockPositionAlgorithm {
mHeight = parentHeight;
mKeyguardStatusHeight = keyguardStatusHeight;
mDarkAmount = dark;
-
- // Where the clock should stop when swiping up.
- // This should be outside of the display when unlocked or
- // under then status bar when the bouncer will be shown
- mClockYTarget = -mKeyguardStatusHeight;
- // TODO: on bouncer animation follow-up CL
- // mClockYTarget = mMinTopMargin + mContainerPadding;
+ mCurrentlySecure = secure;
+ mTracking = tracking;
}
public void run(Result result) {
@@ -173,8 +173,8 @@ public class KeyguardClockPositionAlgorithm {
float y = containerCenter - mKeyguardStatusHeight * CLOCK_HEIGHT_WEIGHT
- mClockNotificationsMargin - mNotificationStackHeight / 2;
- if (y < mMinTopMargin + mContainerPadding) {
- y = mMinTopMargin + mContainerPadding;
+ if (y < mMinTopMargin) {
+ y = mMinTopMargin;
}
// Don't allow the clock base to be under half of the screen
@@ -190,18 +190,32 @@ public class KeyguardClockPositionAlgorithm {
// Dark: Align the bottom edge of the clock at about half of the screen:
final float clockYDark = getMaxClockY() + burnInPreventionOffsetY();
float clockYRegular = getExpandedClockPosition();
+ float clockYTarget = mCurrentlySecure ? mMinTopMargin : -mKeyguardStatusHeight;
// Move clock up while collapsing the shade
final float shadeExpansion = mExpandedHeight / mMaxPanelHeight;
- final float clockY = MathUtils.lerp(mClockYTarget, clockYRegular, shadeExpansion);
+ final float clockY = MathUtils.lerp(clockYTarget, clockYRegular, shadeExpansion);
return (int) MathUtils.lerp(clockY, clockYDark, mDarkAmount);
}
+ /**
+ * We might want to fade out the clock when the user is swiping up.
+ * One exception is when the bouncer will become visible, in this cause the clock
+ * should always persist.
+ *
+ * @param y Current clock Y.
+ * @return Alpha from 0 to 1.
+ */
private float getClockAlpha(int y) {
- float alphaKeyguard = Math.max(0, Math.min(1, (y - mMinTopMargin)
- / Math.max(1f, getExpandedClockPosition() - mMinTopMargin)));
- alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
+ float alphaKeyguard;
+ if (mCurrentlySecure) {
+ alphaKeyguard = 1;
+ } else {
+ alphaKeyguard = Math.max(0, Math.min(1, (y - mMinTopMargin)
+ / Math.max(1f, getExpandedClockPosition() - mMinTopMargin)));
+ alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
+ }
return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 9d2480b2246..2711d7ac7a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -238,7 +238,6 @@ public class NotificationPanelView extends PanelView implements
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private boolean mNoVisibleNotifications = true;
private ValueAnimator mDarkAnimator;
- private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private boolean mUserSetupComplete;
private int mQsNotificationTopPadding;
private float mExpandOffset;
@@ -265,10 +264,8 @@ public class NotificationPanelView extends PanelView implements
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
- mNotificationContainerParent = (NotificationsQuickSettingsContainer)
- findViewById(R.id.notification_container_parent);
- mNotificationStackScroller = (NotificationStackScrollLayout)
- findViewById(R.id.notification_stack_scroller);
+ mNotificationContainerParent = findViewById(R.id.notification_container_parent);
+ mNotificationStackScroller = findViewById(R.id.notification_stack_scroller);
mNotificationStackScroller.setOnHeightChangedListener(this);
mNotificationStackScroller.setOverscrollTopChangedListener(this);
mNotificationStackScroller.setOnEmptySpaceClickListener(this);
@@ -470,7 +467,9 @@ public class NotificationPanelView extends PanelView implements
getMaxPanelHeight(),
totalHeight,
mKeyguardStatusView.getHeight(),
- mDarkAmount);
+ mDarkAmount,
+ mStatusBar.isKeyguardCurrentlySecure(),
+ mTracking);
mClockPositionAlgorithm.run(mClockPositionResult);
if (animate || mClockAnimator != null) {
startClockAnimation(mClockPositionResult.clockX, mClockPositionResult.clockY);
@@ -1710,7 +1709,16 @@ public class NotificationPanelView extends PanelView implements
}
private void updateKeyguardBottomAreaAlpha() {
- float alpha = Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction());
+ // There are two possible panel expansion behaviors:
+ // • User dragging up to unlock: we want to fade out as quick as possible
+ // (ALPHA_EXPANSION_THRESHOLD) to avoid seeing the bouncer over the bottom area.
+ // • User tapping on lock screen: bouncer won't be visible but panel expansion will
+ // change due to "unlock hint animation." In this case, fading out the bottom area
+ // would also hide the message that says "swipe to unlock," we don't want to do that.
+ float expansionAlpha = MathUtils.map(isUnlockHintRunning()
+ ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f,
+ 0f, 1f, getExpandedFraction());
+ float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
mKeyguardBottomArea.setAlpha(alpha);
mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f
? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
@@ -1809,7 +1817,7 @@ public class NotificationPanelView extends PanelView implements
@Override
protected void onTrackingStarted() {
- mFalsingManager.onTrackingStarted();
+ mFalsingManager.onTrackingStarted(mStatusBar.isKeyguardCurrentlySecure());
super.onTrackingStarted();
if (mQsFullyExpanded) {
mQsExpandImmediate = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index cefe97200ca..b448967f6ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -27,6 +27,7 @@ public abstract class PanelBar extends FrameLayout {
public static final boolean DEBUG = false;
public static final String TAG = PanelBar.class.getSimpleName();
private static final boolean SPEW = false;
+ private boolean mBouncerShowing;
public static final void LOG(String fmt, Object... args) {
if (!DEBUG) return;
@@ -65,6 +66,7 @@ public abstract class PanelBar extends FrameLayout {
}
public void setBouncerShowing(boolean showing) {
+ mBouncerShowing = showing;
int important = showing ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: IMPORTANT_FOR_ACCESSIBILITY_AUTO;
@@ -122,7 +124,7 @@ public abstract class PanelBar extends FrameLayout {
boolean fullyOpened = false;
if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
PanelView pv = mPanel;
- pv.setVisibility(expanded ? VISIBLE : INVISIBLE);
+ pv.setVisibility(expanded || mBouncerShowing ? VISIBLE : INVISIBLE);
// adjust any other panels that may be partially visible
if (expanded) {
if (mState == STATE_CLOSED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 7c91a40a7c4..3de0a41dc67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -23,14 +23,8 @@ import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.os.AsyncTask;
-import android.os.Handler;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.os.VibrationEffect;
-import android.os.Vibrator;
-import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.view.InputDevice;
@@ -51,10 +45,10 @@ import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.function.BiConsumer;
public abstract class PanelView extends FrameLayout {
public static final boolean DEBUG = PanelBar.DEBUG;
@@ -69,6 +63,7 @@ public abstract class PanelView extends FrameLayout {
private boolean mVibrateOnOpening;
protected boolean mLaunchingNotification;
private int mFixedDuration = NO_FIXED_DURATION;
+ private BiConsumer mExpansionListener;
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -326,7 +321,8 @@ public abstract class PanelView extends FrameLayout {
cancelPeek();
onTrackingStarted();
}
- if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()) {
+ if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()
+ && !mStatusBar.isBouncerShowing()) {
startOpening(event);
}
break;
@@ -490,7 +486,8 @@ public abstract class PanelView extends FrameLayout {
if (mUpdateFlingOnLayout) {
mUpdateFlingVelocity = vel;
}
- } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking) {
+ } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking
+ && !mStatusBar.isBouncerShowing()) {
long timePassed = SystemClock.uptimeMillis() - mDownTime;
if (timePassed < ViewConfiguration.getLongPressTimeout()) {
// Lets show the user that he can actually expand the panel
@@ -499,7 +496,7 @@ public abstract class PanelView extends FrameLayout {
// We need to collapse the panel since we peeked to the small height.
postOnAnimation(mPostCollapseRunnable);
}
- } else {
+ } else if (!mStatusBar.isBouncerShowing()) {
boolean expands = onEmptySpaceClick(mInitialTouchX);
onTrackingStopped(expands);
}
@@ -1099,6 +1096,10 @@ public abstract class PanelView extends FrameLayout {
mStatusBar.onUnlockHintStarted();
}
+ public boolean isUnlockHintRunning() {
+ return mHintAnimationRunning;
+ }
+
/**
* Phase 1: Move everything upwards.
*/
@@ -1190,6 +1191,13 @@ public abstract class PanelView extends FrameLayout {
mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f
|| mPeekAnimator != null || mInstantExpanding || isPanelVisibleBecauseOfHeadsUp()
|| mTracking || mHeightAnimator != null);
+ if (mExpansionListener != null) {
+ mExpansionListener.accept(mExpandedFraction, mTracking);
+ }
+ }
+
+ public void setExpansionListener(BiConsumer consumer) {
+ mExpansionListener = consumer;
}
protected abstract boolean isPanelVisibleBecauseOfHeadsUp();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index e59a6b56d03..71376a553cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -35,7 +35,6 @@ import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
@@ -97,14 +96,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
* The most common scrim, the one under the keyguard.
*/
protected static final float SCRIM_BEHIND_ALPHA_KEYGUARD = GRADIENT_SCRIM_ALPHA;
- /**
- * We fade out the bottom scrim when the bouncer is visible.
- */
- protected static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
- /**
- * Opacity of the scrim behind the bouncer (the one doing actual background protection.)
- */
- protected static final float SCRIM_IN_FRONT_ALPHA_LOCKED = GRADIENT_SCRIM_ALPHA_BUSY;
static final int TAG_KEY_ANIM = R.id.scrim;
private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
@@ -130,7 +121,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
protected float mScrimBehindAlpha;
protected float mScrimBehindAlphaResValue;
protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
- protected float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
// Assuming the shade is expanded during initialization
private float mExpansionFraction = 1f;
@@ -177,6 +167,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
mScrimVisibleListener = scrimVisibleListener;
mContext = scrimBehind.getContext();
mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
+ mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
mLightBarController = lightBarController;
mScrimBehindAlphaResValue = mContext.getResources().getFloat(R.dimen.scrim_behind_alpha);
@@ -300,10 +291,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
return mState;
}
- protected void setScrimBehindValues(float scrimBehindAlphaKeyguard,
- float scrimBehindAlphaUnlocking) {
+ protected void setScrimBehindValues(float scrimBehindAlphaKeyguard) {
mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
- mScrimBehindAlphaUnlocking = scrimBehindAlphaUnlocking;
ScrimState[] states = ScrimState.values();
for (int i = 0; i < states.length; i++) {
states[i].setScrimBehindAlphaKeyguard(scrimBehindAlphaKeyguard);
@@ -404,9 +393,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
float interpolatedFract = getInterpolatedFraction();
float alphaBehind = mState.getBehindAlpha(mNotificationDensity);
if (mDarkenWhileDragging) {
- mCurrentBehindAlpha = MathUtils.lerp(mScrimBehindAlphaUnlocking, alphaBehind,
+ mCurrentBehindAlpha = MathUtils.lerp(GRADIENT_SCRIM_ALPHA_BUSY, alphaBehind,
interpolatedFract);
- mCurrentInFrontAlpha = (1f - interpolatedFract) * SCRIM_IN_FRONT_ALPHA_LOCKED;
+ mCurrentInFrontAlpha = 0;
} else {
mCurrentBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind,
interpolatedFract);
@@ -455,7 +444,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
if (mNeedsDrawableColorUpdate) {
mNeedsDrawableColorUpdate = false;
final GradientColors currentScrimColors;
- if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER) {
+ if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER_OCCLUDED
+ || mState == ScrimState.BOUNCER) {
// Always animate color changes if we're seeing the keyguard
mScrimInFront.setColors(mLockColors, true /* animated */);
mScrimBehind.setColors(mLockColors, true /* animated */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 053c5a3b596..58100efbcf8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -66,20 +66,31 @@ public enum ScrimState {
},
/**
- * Showing password challenge.
+ * Showing password challenge on the keyguard.
*/
BOUNCER(1) {
@Override
public void prepare(ScrimState previousState) {
- mCurrentBehindAlpha = ScrimController.SCRIM_BEHIND_ALPHA_UNLOCKING;
- mCurrentInFrontAlpha = ScrimController.SCRIM_IN_FRONT_ALPHA_LOCKED;
+ mCurrentBehindAlpha = ScrimController.GRADIENT_SCRIM_ALPHA_BUSY;
+ mCurrentInFrontAlpha = 0f;
+ }
+ },
+
+ /**
+ * Showing password challenge on top of a FLAG_SHOW_WHEN_LOCKED activity.
+ */
+ BOUNCER_OCCLUDED(2) {
+ @Override
+ public void prepare(ScrimState previousState) {
+ mCurrentBehindAlpha = 0;
+ mCurrentInFrontAlpha = ScrimController.GRADIENT_SCRIM_ALPHA_BUSY;
}
},
/**
* Changing screen brightness from quick settings.
*/
- BRIGHTNESS_MIRROR(2) {
+ BRIGHTNESS_MIRROR(3) {
@Override
public void prepare(ScrimState previousState) {
mCurrentBehindAlpha = 0;
@@ -90,7 +101,7 @@ public enum ScrimState {
/**
* Always on display or screen off.
*/
- AOD(3) {
+ AOD(4) {
@Override
public void prepare(ScrimState previousState) {
final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
@@ -110,7 +121,7 @@ public enum ScrimState {
/**
* When phone wakes up because you received a notification.
*/
- PULSING(4) {
+ PULSING(5) {
@Override
public void prepare(ScrimState previousState) {
mCurrentInFrontAlpha = 0;
@@ -125,7 +136,7 @@ public enum ScrimState {
/**
* Unlocked on top of an app (launcher or any other activity.)
*/
- UNLOCKED(5) {
+ UNLOCKED(6) {
@Override
public void prepare(ScrimState previousState) {
mCurrentBehindAlpha = 0;
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 899b93626a7..a305bfc7b0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1296,7 +1296,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mDozeScrimController, keyguardViewMediator,
mScrimController, this, UnlockMethodCache.getInstance(mContext));
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
- getBouncerContainer(), mFingerprintUnlockController);
+ getBouncerContainer(), mNotificationPanel, mFingerprintUnlockController);
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
@@ -4619,7 +4619,8 @@ public class StatusBar extends SystemUI implements DemoMode,
== FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
if (mBouncerShowing) {
- mScrimController.transitionTo(ScrimState.BOUNCER);
+ mScrimController.transitionTo(
+ mIsOccluded ? ScrimState.BOUNCER_OCCLUDED : ScrimState.BOUNCER);
} else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
} else if (mBrightnessMirrorVisible) {
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 a009d80dad4..8d536d8ca45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -31,10 +31,10 @@ import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
+import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.internal.util.LatencyTracker;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dependency;
@@ -75,6 +75,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
protected LockPatternUtils mLockPatternUtils;
protected ViewMediatorCallback mViewMediatorCallback;
protected StatusBar mStatusBar;
+ private NotificationPanelView mNotificationPanelView;
private FingerprintUnlockController mFingerprintUnlockController;
private ViewGroup mContainer;
@@ -88,6 +89,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
protected boolean mFirstUpdate = true;
protected boolean mLastShowing;
protected boolean mLastOccluded;
+ private boolean mLastTracking;
private boolean mLastBouncerShowing;
private boolean mLastBouncerDismissible;
protected boolean mLastRemoteInputActive;
@@ -124,6 +126,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
public void registerStatusBar(StatusBar statusBar,
ViewGroup container,
+ NotificationPanelView notificationPanelView,
FingerprintUnlockController fingerprintUnlockController,
DismissCallbackRegistry dismissCallbackRegistry) {
mStatusBar = statusBar;
@@ -131,6 +134,32 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mFingerprintUnlockController = fingerprintUnlockController;
mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry);
+ mNotificationPanelView = notificationPanelView;
+ notificationPanelView.setExpansionListener(this::onPanelExpansionChanged);
+ }
+
+ private void onPanelExpansionChanged(float expansion, boolean tracking) {
+ // We don't want to translate the bounce when the keyguard is occluded, because we're in
+ // a FLAG_SHOW_WHEN_LOCKED activity and need to conserve the original animation.
+ // We also don't want to show the bouncer when the user quickly taps on the display.
+ final boolean noLongerTracking = mLastTracking != tracking && !tracking;
+ if (mOccluded || mNotificationPanelView.isUnlockHintRunning()) {
+ mBouncer.setExpansion(0);
+ } else if (mShowing && mStatusBar.isKeyguardCurrentlySecure() && !mDozing) {
+ mBouncer.setExpansion(expansion);
+ if (expansion == 1) {
+ mBouncer.onFullyHidden();
+ updateStates();
+ } else if (!mBouncer.isShowing()) {
+ mBouncer.show(true /* resetSecuritySelection */, false /* notifyFalsing */);
+ } else if (noLongerTracking) {
+ // Notify that falsing manager should stop its session when user stops touching,
+ // even before the animation ends, to guarantee that we're not recording sensitive
+ // data.
+ mBouncer.onFullyShown();
+ }
+ }
+ mLastTracking = tracking;
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 3ed2fe14a0b..bfa469eba99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -170,12 +170,22 @@ public class ScrimControllerTest extends SysuiTestCase {
}
@Test
- public void transitionToBouncer() {
+ public void transitionToKeyguardBouncer() {
mScrimController.transitionTo(ScrimState.BOUNCER);
mScrimController.finishAnimationsImmediately();
// Front scrim should be transparent
// Back scrim should be visible without tint
- assertScrimVisibility(VISIBILITY_SEMI_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
+ assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
+ assertScrimTint(mScrimBehind, false /* tinted */);
+ }
+
+ @Test
+ public void transitionToBouncer() {
+ mScrimController.transitionTo(ScrimState.BOUNCER_OCCLUDED);
+ mScrimController.finishAnimationsImmediately();
+ // Front scrim should be transparent
+ // Back scrim should be visible without tint
+ assertScrimVisibility(VISIBILITY_SEMI_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT);
assertScrimTint(mScrimBehind, false /* tinted */);
}
--
GitLab
From 90d3aa099560b48a64c490b6db5ea5f03d068f15 Mon Sep 17 00:00:00 2001
From: Tej Singh
Date: Thu, 8 Mar 2018 19:07:58 -0800
Subject: [PATCH 045/488] Logging in StatsCompanionService
Converted a lot of log lines to debug and turned them off by default.
Bug: 72567474
Test: none
Change-Id: I46ca0609648e64b862a56e5f5d445c91a3e889da
---
.../java/com/android/server/stats/StatsCompanionService.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 64a2570c563..986704b5e26 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -278,7 +278,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
&& intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
return; // Keep only replacing or normal add and remove.
}
- Slog.i(TAG, "StatsCompanionService noticed an app was updated.");
+ if (DEBUG) Slog.d(TAG, "StatsCompanionService noticed an app was updated.");
synchronized (sStatsdLock) {
if (sStatsd == null) {
Slog.w(TAG, "Could not access statsd to inform it of an app update");
--
GitLab
From 2f4d2af93a25020175ff93f7fb6088b7360ef413 Mon Sep 17 00:00:00 2001
From: Vadim Tryshev
Date: Fri, 9 Mar 2018 11:08:53 -0800
Subject: [PATCH 046/488] Adding generation of ACTION_TOGGLE_RECENTS to shared
lib
Bug: 72967764
Test: atest google/perf/app-transition/sysui-latency-test, watch for 1_*
entries in output
Change-Id: I0bfaa46df4f3167687099742cb3063e88dab30ae
---
.../android/internal/util/LatencyTracker.java | 13 +++++--
.../shared/system/LatencyTrackerCompat.java | 34 +++++++++++++++++++
2 files changed, 45 insertions(+), 2 deletions(-)
create mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 72cd24888dc..6c3a58ce390 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -147,8 +147,17 @@ public class LatencyTracker {
}
mStartRtc.delete(action);
Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, NAMES[action], 0);
- long duration = endRtc - startRtc;
+ logAction(action, (int)(endRtc - startRtc));
+ }
+
+ /**
+ * Logs an action that has started and ended. This needs to be called from the main thread.
+ *
+ * @param action The action to end. One of the ACTION_* values.
+ * @param duration The duration of the action in ms.
+ */
+ public static void logAction(int action, int duration) {
Log.i(TAG, "action=" + action + " latency=" + duration);
- EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, (int) duration);
+ EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, duration);
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
new file mode 100644
index 00000000000..0d5933e5f59
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.system;
+
+import android.content.Context;
+
+import com.android.internal.util.LatencyTracker;
+
+/**
+ * @see LatencyTracker
+ */
+public class LatencyTrackerCompat {
+ public static boolean isEnabled(Context context) {
+ return LatencyTracker.isEnabled(context);
+ }
+
+ public static void logToggleRecents(int duration) {
+ LatencyTracker.logAction(LatencyTracker.ACTION_TOGGLE_RECENTS, duration);
+ }
+}
\ No newline at end of file
--
GitLab
From 338438b389a93686de596150324483bddc78494e Mon Sep 17 00:00:00 2001
From: Marco Nelissen
Date: Tue, 7 Nov 2017 13:52:02 -0800
Subject: [PATCH 047/488] Rework thumbnail cleanup -- DO NOT MERGE
Bug: 63766886
Test: ran CTS tests
Change-Id: I1f92bb014e275eafe3f42aef1f8c817f187c6608
Merged-In: I1f92bb014e275eafe3f42aef1f8c817f187c6608
---
core/java/android/provider/MediaStore.java | 4 +-
media/java/android/media/MediaScanner.java | 52 --------------------
media/java/android/media/MiniThumbFile.java | 54 ++++++++++++++++++++-
3 files changed, 54 insertions(+), 56 deletions(-)
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 13e1e26b51c..ff4f358529a 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -694,8 +694,8 @@ public final class MediaStore {
// Log.v(TAG, "getThumbnail: origId="+origId+", kind="+kind+", isVideo="+isVideo);
// If the magic is non-zero, we simply return thumbnail if it does exist.
// querying MediaProvider and simply return thumbnail.
- MiniThumbFile thumbFile = new MiniThumbFile(isVideo ? Video.Media.EXTERNAL_CONTENT_URI
- : Images.Media.EXTERNAL_CONTENT_URI);
+ MiniThumbFile thumbFile = MiniThumbFile.instance(
+ isVideo ? Video.Media.EXTERNAL_CONTENT_URI : Images.Media.EXTERNAL_CONTENT_URI);
Cursor c = null;
try {
long magic = thumbFile.getMagic(origId);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index ddfa0258ab9..40161e3a95d 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -323,7 +323,6 @@ public class MediaScanner implements AutoCloseable {
private final Uri mAudioUri;
private final Uri mVideoUri;
private final Uri mImagesUri;
- private final Uri mThumbsUri;
private final Uri mPlaylistsUri;
private final Uri mFilesUri;
private final Uri mFilesUriNoNotify;
@@ -419,7 +418,6 @@ public class MediaScanner implements AutoCloseable {
mAudioUri = Audio.Media.getContentUri(volumeName);
mVideoUri = Video.Media.getContentUri(volumeName);
mImagesUri = Images.Media.getContentUri(volumeName);
- mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
mFilesUri = Files.getContentUri(volumeName);
mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
@@ -1283,53 +1281,6 @@ public class MediaScanner implements AutoCloseable {
}
}
- private void pruneDeadThumbnailFiles() {
- HashSet existingFiles = new HashSet();
- String directory = "/sdcard/DCIM/.thumbnails";
- String [] files = (new File(directory)).list();
- Cursor c = null;
- if (files == null)
- files = new String[0];
-
- for (int i = 0; i < files.length; i++) {
- String fullPathString = directory + "/" + files[i];
- existingFiles.add(fullPathString);
- }
-
- try {
- c = mMediaProvider.query(
- mThumbsUri,
- new String [] { "_data" },
- null,
- null,
- null, null);
- Log.v(TAG, "pruneDeadThumbnailFiles... " + c);
- if (c != null && c.moveToFirst()) {
- do {
- String fullPathString = c.getString(0);
- existingFiles.remove(fullPathString);
- } while (c.moveToNext());
- }
-
- for (String fileToDelete : existingFiles) {
- if (false)
- Log.v(TAG, "fileToDelete is " + fileToDelete);
- try {
- (new File(fileToDelete)).delete();
- } catch (SecurityException ex) {
- }
- }
-
- Log.v(TAG, "/pruneDeadThumbnailFiles... " + c);
- } catch (RemoteException e) {
- // We will soon be killed...
- } finally {
- if (c != null) {
- c.close();
- }
- }
- }
-
static class MediaBulkDeleter {
StringBuilder whereClause = new StringBuilder();
ArrayList whereArgs = new ArrayList(100);
@@ -1373,9 +1324,6 @@ public class MediaScanner implements AutoCloseable {
processPlayLists();
}
- if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external")))
- pruneDeadThumbnailFiles();
-
// allow GC to clean up
mPlayLists.clear();
}
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index 664308c45bf..98993676ce4 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -44,13 +44,14 @@ import java.util.Hashtable;
*/
public class MiniThumbFile {
private static final String TAG = "MiniThumbFile";
- private static final int MINI_THUMB_DATA_FILE_VERSION = 3;
+ private static final int MINI_THUMB_DATA_FILE_VERSION = 4;
public static final int BYTES_PER_MINTHUMB = 10000;
private static final int HEADER_SIZE = 1 + 8 + 4;
private Uri mUri;
private RandomAccessFile mMiniThumbFile;
private FileChannel mChannel;
private ByteBuffer mBuffer;
+ private ByteBuffer mEmptyBuffer;
private static final Hashtable sThumbFiles =
new Hashtable();
@@ -127,9 +128,10 @@ public class MiniThumbFile {
return mMiniThumbFile;
}
- public MiniThumbFile(Uri uri) {
+ private MiniThumbFile(Uri uri) {
mUri = uri;
mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
+ mEmptyBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
}
public synchronized void deactivate() {
@@ -184,6 +186,54 @@ public class MiniThumbFile {
return 0;
}
+ public synchronized void eraseMiniThumb(long id) {
+ RandomAccessFile r = miniThumbDataFile();
+ if (r != null) {
+ long pos = id * BYTES_PER_MINTHUMB;
+ FileLock lock = null;
+ try {
+ mBuffer.clear();
+ mBuffer.limit(1 + 8);
+
+ lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false);
+ // check that we can read the following 9 bytes
+ // (1 for the "status" and 8 for the long)
+ if (mChannel.read(mBuffer, pos) == 9) {
+ mBuffer.position(0);
+ if (mBuffer.get() == 1) {
+ long currentMagic = mBuffer.getLong();
+ if (currentMagic == 0) {
+ // there is no thumbnail stored here
+ Log.i(TAG, "no thumbnail for id " + id);
+ return;
+ }
+ // zero out the thumbnail slot
+ // Log.v(TAG, "clearing slot " + id + ", magic " + currentMagic
+ // + " at offset " + pos);
+ mChannel.write(mEmptyBuffer, pos);
+ }
+ } else {
+ // Log.v(TAG, "No slot");
+ }
+ } catch (IOException ex) {
+ Log.v(TAG, "Got exception checking file magic: ", ex);
+ } catch (RuntimeException ex) {
+ // Other NIO related exception like disk full, read only channel..etc
+ Log.e(TAG, "Got exception when reading magic, id = " + id +
+ ", disk full or mount read-only? " + ex.getClass());
+ } finally {
+ try {
+ if (lock != null) lock.release();
+ }
+ catch (IOException ex) {
+ // ignore it.
+ }
+ }
+ } else {
+ // Log.v(TAG, "No data file");
+ }
+ }
+
public synchronized void saveMiniThumbToFile(byte[] data, long id, long magic)
throws IOException {
RandomAccessFile r = miniThumbDataFile();
--
GitLab
From f1d939910f1c9580297878cd13784a0f4b3be3a4 Mon Sep 17 00:00:00 2001
From: Abodunrinwa Toki
Date: Fri, 2 Mar 2018 13:53:21 +0000
Subject: [PATCH 048/488] Merge textclassifier/logging/ into textclassifier/
This is based on feedback on Ib5af1ec80a38432d1201fbc913acdc3597d6ba82
Bug: 74466564
Bug: 67609167
Test: bit FrameworksCoreTests:android.view.textclassifier.TextClassificationManagerTest
Test: bit CtsWidgetTestCases:android.widget.cts.TextViewTest
Test: bit FrameworksCoreTests:android.widget.TextViewActivityTest
Test: bit CtsViewTestCases:android.view.textclassifier.cts.TextClassificationManagerTest
Test: bit CtsViewTestCases:android.view.textclassifier.cts.LoggerTest
Merged-In: Ic8d58acb2bbd63cedcac4aa16940b4ac852aadc8
Change-Id: Ic8d58acb2bbd63cedcac4aa16940b4ac852aadc8
---
api/current.txt | 142 +++++++++---------
.../{logging => }/DefaultLogger.java | 2 +-
.../{logging => }/GenerateLinksLogger.java | 4 +-
.../textclassifier/{logging => }/Logger.java | 5 +-
.../{logging => }/SelectionEvent.java | 2 +-
.../view/textclassifier/TextClassifier.java | 1 -
.../textclassifier/TextClassifierImpl.java | 3 -
.../widget/SelectionActionModeHelper.java | 4 +-
.../logging/GenerateLinksLoggerTest.java | 1 +
9 files changed, 76 insertions(+), 88 deletions(-)
rename core/java/android/view/textclassifier/{logging => }/DefaultLogger.java (99%)
rename core/java/android/view/textclassifier/{logging => }/GenerateLinksLogger.java (97%)
rename core/java/android/view/textclassifier/{logging => }/Logger.java (98%)
rename core/java/android/view/textclassifier/{logging => }/SelectionEvent.java (99%)
diff --git a/api/current.txt b/api/current.txt
index 2875e34de04..1e4229dae3f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -51036,6 +51036,74 @@ package android.view.inputmethod {
package android.view.textclassifier {
+ public abstract class Logger {
+ ctor public Logger(android.view.textclassifier.Logger.Config);
+ method public java.text.BreakIterator getTokenIterator(java.util.Locale);
+ method public boolean isSmartSelection(java.lang.String);
+ method public final void logSelectionActionEvent(int, int, int);
+ method public final void logSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification);
+ method public final void logSelectionModifiedEvent(int, int);
+ method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
+ method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
+ method public final void logSelectionStartedEvent(int, int);
+ method public abstract void writeEvent(android.view.textclassifier.SelectionEvent);
+ field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff
+ field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000
+ field public static final java.lang.String WIDGET_CUSTOM_EDITTEXT = "customedit";
+ field public static final java.lang.String WIDGET_CUSTOM_TEXTVIEW = "customview";
+ field public static final java.lang.String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
+ field public static final java.lang.String WIDGET_EDITTEXT = "edittext";
+ field public static final java.lang.String WIDGET_EDIT_WEBVIEW = "edit-webview";
+ field public static final java.lang.String WIDGET_TEXTVIEW = "textview";
+ field public static final java.lang.String WIDGET_UNKNOWN = "unknown";
+ field public static final java.lang.String WIDGET_UNSELECTABLE_TEXTVIEW = "nosel-textview";
+ field public static final java.lang.String WIDGET_WEBVIEW = "webview";
+ }
+
+ public static final class Logger.Config {
+ ctor public Logger.Config(android.content.Context, java.lang.String, java.lang.String);
+ method public java.lang.String getPackageName();
+ method public java.lang.String getWidgetType();
+ method public java.lang.String getWidgetVersion();
+ }
+
+ public final class SelectionEvent {
+ method public long getDurationSincePreviousEvent();
+ method public long getDurationSinceSessionStart();
+ method public int getEnd();
+ method public java.lang.String getEntityType();
+ method public int getEventIndex();
+ method public long getEventTime();
+ method public int getEventType();
+ method public int getInvocationMethod();
+ method public java.lang.String getPackageName();
+ method public java.lang.String getSessionId();
+ method public java.lang.String getSignature();
+ method public int getSmartEnd();
+ method public int getSmartStart();
+ method public int getStart();
+ method public java.lang.String getWidgetType();
+ method public java.lang.String getWidgetVersion();
+ field public static final int ACTION_ABANDON = 107; // 0x6b
+ field public static final int ACTION_COPY = 101; // 0x65
+ field public static final int ACTION_CUT = 103; // 0x67
+ field public static final int ACTION_DRAG = 106; // 0x6a
+ field public static final int ACTION_OTHER = 108; // 0x6c
+ field public static final int ACTION_OVERTYPE = 100; // 0x64
+ field public static final int ACTION_PASTE = 102; // 0x66
+ field public static final int ACTION_RESET = 201; // 0xc9
+ field public static final int ACTION_SELECT_ALL = 200; // 0xc8
+ field public static final int ACTION_SHARE = 104; // 0x68
+ field public static final int ACTION_SMART_SHARE = 105; // 0x69
+ field public static final int EVENT_AUTO_SELECTION = 5; // 0x5
+ field public static final int EVENT_SELECTION_MODIFIED = 2; // 0x2
+ field public static final int EVENT_SELECTION_STARTED = 1; // 0x1
+ field public static final int EVENT_SMART_SELECTION_MULTI = 4; // 0x4
+ field public static final int EVENT_SMART_SELECTION_SINGLE = 3; // 0x3
+ field public static final int INVOCATION_LINK = 2; // 0x2
+ field public static final int INVOCATION_MANUAL = 1; // 0x1
+ }
+
public final class TextClassification implements android.os.Parcelable {
method public int describeContents();
method public float getConfidenceScore(java.lang.String);
@@ -51092,7 +51160,7 @@ package android.view.textclassifier {
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options);
method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence);
- method public default android.view.textclassifier.logging.Logger getLogger(android.view.textclassifier.logging.Logger.Config);
+ method public default android.view.textclassifier.Logger getLogger(android.view.textclassifier.Logger.Config);
method public default int getMaxGenerateLinksTextLength();
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
@@ -51205,78 +51273,6 @@ package android.view.textclassifier {
}
-package android.view.textclassifier.logging {
-
- public abstract class Logger {
- ctor public Logger(android.view.textclassifier.logging.Logger.Config);
- method public java.text.BreakIterator getTokenIterator(java.util.Locale);
- method public boolean isSmartSelection(java.lang.String);
- method public final void logSelectionActionEvent(int, int, int);
- method public final void logSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification);
- method public final void logSelectionModifiedEvent(int, int);
- method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
- method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
- method public final void logSelectionStartedEvent(int, int);
- method public abstract void writeEvent(android.view.textclassifier.logging.SelectionEvent);
- field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff
- field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000
- field public static final java.lang.String WIDGET_CUSTOM_EDITTEXT = "customedit";
- field public static final java.lang.String WIDGET_CUSTOM_TEXTVIEW = "customview";
- field public static final java.lang.String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
- field public static final java.lang.String WIDGET_EDITTEXT = "edittext";
- field public static final java.lang.String WIDGET_EDIT_WEBVIEW = "edit-webview";
- field public static final java.lang.String WIDGET_TEXTVIEW = "textview";
- field public static final java.lang.String WIDGET_UNKNOWN = "unknown";
- field public static final java.lang.String WIDGET_UNSELECTABLE_TEXTVIEW = "nosel-textview";
- field public static final java.lang.String WIDGET_WEBVIEW = "webview";
- }
-
- public static final class Logger.Config {
- ctor public Logger.Config(android.content.Context, java.lang.String, java.lang.String);
- method public java.lang.String getPackageName();
- method public java.lang.String getWidgetType();
- method public java.lang.String getWidgetVersion();
- }
-
- public final class SelectionEvent {
- method public long getDurationSincePreviousEvent();
- method public long getDurationSinceSessionStart();
- method public int getEnd();
- method public java.lang.String getEntityType();
- method public int getEventIndex();
- method public long getEventTime();
- method public int getEventType();
- method public int getInvocationMethod();
- method public java.lang.String getPackageName();
- method public java.lang.String getSessionId();
- method public java.lang.String getSignature();
- method public int getSmartEnd();
- method public int getSmartStart();
- method public int getStart();
- method public java.lang.String getWidgetType();
- method public java.lang.String getWidgetVersion();
- field public static final int ACTION_ABANDON = 107; // 0x6b
- field public static final int ACTION_COPY = 101; // 0x65
- field public static final int ACTION_CUT = 103; // 0x67
- field public static final int ACTION_DRAG = 106; // 0x6a
- field public static final int ACTION_OTHER = 108; // 0x6c
- field public static final int ACTION_OVERTYPE = 100; // 0x64
- field public static final int ACTION_PASTE = 102; // 0x66
- field public static final int ACTION_RESET = 201; // 0xc9
- field public static final int ACTION_SELECT_ALL = 200; // 0xc8
- field public static final int ACTION_SHARE = 104; // 0x68
- field public static final int ACTION_SMART_SHARE = 105; // 0x69
- field public static final int EVENT_AUTO_SELECTION = 5; // 0x5
- field public static final int EVENT_SELECTION_MODIFIED = 2; // 0x2
- field public static final int EVENT_SELECTION_STARTED = 1; // 0x1
- field public static final int EVENT_SMART_SELECTION_MULTI = 4; // 0x4
- field public static final int EVENT_SMART_SELECTION_SINGLE = 3; // 0x3
- field public static final int INVOCATION_LINK = 2; // 0x2
- field public static final int INVOCATION_MANUAL = 1; // 0x1
- }
-
-}
-
package android.view.textservice {
public final class SentenceSuggestionsInfo implements android.os.Parcelable {
diff --git a/core/java/android/view/textclassifier/logging/DefaultLogger.java b/core/java/android/view/textclassifier/DefaultLogger.java
similarity index 99%
rename from core/java/android/view/textclassifier/logging/DefaultLogger.java
rename to core/java/android/view/textclassifier/DefaultLogger.java
index f510879cf40..b2f4e399da5 100644
--- a/core/java/android/view/textclassifier/logging/DefaultLogger.java
+++ b/core/java/android/view/textclassifier/DefaultLogger.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.textclassifier.logging;
+package android.view.textclassifier;
import android.annotation.NonNull;
import android.content.Context;
diff --git a/core/java/android/view/textclassifier/logging/GenerateLinksLogger.java b/core/java/android/view/textclassifier/GenerateLinksLogger.java
similarity index 97%
rename from core/java/android/view/textclassifier/logging/GenerateLinksLogger.java
rename to core/java/android/view/textclassifier/GenerateLinksLogger.java
index fb6f205eb46..73cf43b87ea 100644
--- a/core/java/android/view/textclassifier/logging/GenerateLinksLogger.java
+++ b/core/java/android/view/textclassifier/GenerateLinksLogger.java
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package android.view.textclassifier.logging;
+package android.view.textclassifier;
import android.annotation.Nullable;
import android.metrics.LogMaker;
import android.util.ArrayMap;
import android.util.Log;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextLinks;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
diff --git a/core/java/android/view/textclassifier/logging/Logger.java b/core/java/android/view/textclassifier/Logger.java
similarity index 98%
rename from core/java/android/view/textclassifier/logging/Logger.java
rename to core/java/android/view/textclassifier/Logger.java
index 4448b2b5b49..a4f5bf17066 100644
--- a/core/java/android/view/textclassifier/logging/Logger.java
+++ b/core/java/android/view/textclassifier/Logger.java
@@ -14,16 +14,13 @@
* limitations under the License.
*/
-package android.view.textclassifier.logging;
+package android.view.textclassifier;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
import android.content.Context;
import android.util.Log;
-import android.view.textclassifier.TextClassification;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextSelection;
import com.android.internal.util.Preconditions;
diff --git a/core/java/android/view/textclassifier/logging/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
similarity index 99%
rename from core/java/android/view/textclassifier/logging/SelectionEvent.java
rename to core/java/android/view/textclassifier/SelectionEvent.java
index a8de3088d8c..90fd921b024 100644
--- a/core/java/android/view/textclassifier/logging/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.textclassifier.logging;
+package android.view.textclassifier;
import android.annotation.IntDef;
import android.annotation.Nullable;
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index ec40fdd0ffb..ebd2ff983bc 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -28,7 +28,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
import android.util.Slog;
-import android.view.textclassifier.logging.Logger;
import com.android.internal.util.Preconditions;
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 41f1c69a47e..0a052699590 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -34,9 +34,6 @@ import android.os.UserManager;
import android.provider.Browser;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
-import android.view.textclassifier.logging.DefaultLogger;
-import android.view.textclassifier.logging.GenerateLinksLogger;
-import android.view.textclassifier.logging.Logger;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 8e93078fb1b..629f5319281 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -33,13 +33,13 @@ import android.text.Spannable;
import android.text.TextUtils;
import android.util.Log;
import android.view.ActionMode;
+import android.view.textclassifier.Logger;
+import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationConstants;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextSelection;
-import android.view.textclassifier.logging.Logger;
-import android.view.textclassifier.logging.SelectionEvent;
import android.widget.Editor.SelectionModifierCursorController;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
index b920ca30d6a..8e4f02c668b 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
@@ -26,6 +26,7 @@ import android.metrics.LogMaker;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
+import android.view.textclassifier.GenerateLinksLogger;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
--
GitLab
From 3fa5d7fb236f263125bc6364ea693e5e9f122976 Mon Sep 17 00:00:00 2001
From: Yangster-mac
Date: Sat, 10 Mar 2018 21:50:27 -0800
Subject: [PATCH 049/488] Add wall clock timestamp for ConfigMetricsReport and
gauge atoms.
Fix the bug when serializing multiple atoms in gauge metric
BUG: b/74159560
Test: new test for ALL_CONDITION_CHANGES sampling method.
Change-Id: I6d33c1efbac92b6e13be2d64c323e090cb1f84aa
---
cmds/statsd/Android.mk | 2 +-
cmds/statsd/src/StatsLogProcessor.cpp | 9 +
.../src/metrics/GaugeMetricProducer.cpp | 20 +-
cmds/statsd/src/metrics/MetricsManager.cpp | 5 +-
cmds/statsd/src/metrics/MetricsManager.h | 9 +-
cmds/statsd/src/stats_log.proto | 8 +-
.../tests/e2e/GaugeMetric_e2e_push_test.cpp | 281 ++++++++++++++++++
.../statsd/tests/e2e/GaugeMetric_e2e_test.cpp | 201 -------------
8 files changed, 323 insertions(+), 212 deletions(-)
create mode 100644 cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
delete mode 100644 cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 7f0a26c1714..14180656e5c 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -198,7 +198,7 @@ LOCAL_SRC_FILES := \
tests/e2e/WakelockDuration_e2e_test.cpp \
tests/e2e/MetricConditionLink_e2e_test.cpp \
tests/e2e/Attribution_e2e_test.cpp \
- tests/e2e/GaugeMetric_e2e_test.cpp \
+ tests/e2e/GaugeMetric_e2e_push_test.cpp \
tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp \
tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp \
tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 02d4dc985e8..8f72a8f0958 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -62,6 +62,9 @@ const int FIELD_ID_ID = 2;
const int FIELD_ID_UID_MAP = 2;
const int FIELD_ID_LAST_REPORT_ELAPSED_NANOS = 3;
const int FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS = 4;
+const int FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS = 5;
+const int FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS = 6;
+
#define STATS_DATA_DIR "/data/misc/stats-data"
@@ -260,6 +263,8 @@ void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t
proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
+ int64_t lastReportWallClockNs = it->second->getLastReportWallClockNs();
+
// First, fill in ConfigMetricsReport using current data on memory, which
// starts from filling in StatsLogReport's.
it->second->onDumpReport(dumpTimeStampNs, &proto);
@@ -276,6 +281,10 @@ void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t
(long long)lastReportTimeNs);
proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
(long long)dumpTimeStampNs);
+ proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS,
+ (long long)lastReportWallClockNs);
+ proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS,
+ (long long)getWallClockNs());
// End of ConfigMetricsReport (reports).
proto.end(reportsToken);
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index e479e5caec2..9ac1bca1a90 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -56,6 +56,7 @@ const int FIELD_ID_START_BUCKET_ELAPSED_NANOS = 1;
const int FIELD_ID_END_BUCKET_ELAPSED_NANOS = 2;
const int FIELD_ID_ATOM = 3;
const int FIELD_ID_ELAPSED_ATOM_TIMESTAMP = 4;
+const int FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP = 5;
GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
const int conditionIndex,
@@ -168,21 +169,28 @@ void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
(long long)bucket.mBucketEndNs);
if (!bucket.mGaugeAtoms.empty()) {
- uint64_t atomsToken =
- protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
for (const auto& atom : bucket.mGaugeAtoms) {
+ uint64_t atomsToken =
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ FIELD_ID_ATOM);
writeFieldValueTreeToStream(mTagId, *(atom.mFields), protoOutput);
+ protoOutput->end(atomsToken);
}
- protoOutput->end(atomsToken);
+ const bool truncateTimestamp =
+ android::util::kNotTruncatingTimestampAtomWhiteList.find(mTagId) ==
+ android::util::kNotTruncatingTimestampAtomWhiteList.end();
+ const int64_t wall_clock_ns = truncateTimestamp ?
+ truncateTimestampNsToFiveMinutes(getWallClockNs()) : getWallClockNs();
for (const auto& atom : bucket.mGaugeAtoms) {
- const bool truncateTimestamp =
- android::util::kNotTruncatingTimestampAtomWhiteList.find(mTagId) ==
- android::util::kNotTruncatingTimestampAtomWhiteList.end();
int64_t timestampNs = truncateTimestamp ?
truncateTimestampNsToFiveMinutes(atom.mTimestamps) : atom.mTimestamps;
protoOutput->write(
FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_ELAPSED_ATOM_TIMESTAMP,
(long long)timestampNs);
+ protoOutput->write(
+ FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED |
+ FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP,
+ (long long)wall_clock_ns);
}
}
protoOutput->end(bucketInfoToken);
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 1ca59a366fc..6209bbe7581 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -53,7 +53,9 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
const sp &uidMap,
const sp& anomalyAlarmMonitor,
const sp& periodicAlarmMonitor)
- : mConfigKey(key), mUidMap(uidMap), mLastReportTimeNs(timeBaseSec * NS_PER_SEC) {
+ : mConfigKey(key), mUidMap(uidMap),
+ mLastReportTimeNs(timeBaseSec * NS_PER_SEC),
+ mLastReportWallClockNs(getWallClockNs()) {
mConfigValid =
initStatsdConfig(key, config, *uidMap, anomalyAlarmMonitor, periodicAlarmMonitor,
timeBaseSec, mTagIds, mAllAtomMatchers,
@@ -193,6 +195,7 @@ void MetricsManager::onDumpReport(const uint64_t dumpTimeStampNs, ProtoOutputStr
}
}
mLastReportTimeNs = dumpTimeStampNs;
+ mLastReportWallClockNs = getWallClockNs();
VLOG("=========================Metric Reports End==========================");
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index dbab8143174..bebd53c2988 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -69,10 +69,14 @@ public:
void dumpStates(FILE* out, bool verbose);
// Returns the elapsed realtime when this metric manager last reported metrics.
- uint64_t getLastReportTimeNs() {
+ inline int64_t getLastReportTimeNs() const {
return mLastReportTimeNs;
};
+ inline int64_t getLastReportWallClockNs() const {
+ return mLastReportWallClockNs;
+ };
+
virtual void dropData(const uint64_t dropTimeNs);
// Config source owner can call onDumpReport() to get all the metrics collected.
@@ -89,7 +93,8 @@ private:
bool mConfigValid = false;
- uint64_t mLastReportTimeNs;
+ int64_t mLastReportTimeNs;
+ int64_t mLastReportWallClockNs;
// The uid log sources from StatsdConfig.
std::vector mAllowedUid;
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 3c5f5a2b990..0412538ef05 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -46,7 +46,7 @@ message EventMetricData {
optional Atom atom = 2;
- optional int64 wall_clock_timestamp_sec = 3;
+ optional int64 wall_clock_timestamp_nanos = 3;
}
message CountBucketInfo {
@@ -105,6 +105,8 @@ message GaugeBucketInfo {
repeated Atom atom = 3;
repeated int64 elapsed_timestamp_nanos = 4;
+
+ repeated int64 wall_clock_timestamp_nanos = 5;
}
message GaugeMetricData {
@@ -154,6 +156,10 @@ message ConfigMetricsReport {
optional int64 last_report_elapsed_nanos = 3;
optional int64 current_report_elapsed_nanos = 4;
+
+ optional int64 last_report_wall_clock_nanos = 5;
+
+ optional int64 current_report_wall_clock_nanos = 6;
}
message ConfigMetricsReportList {
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
new file mode 100644
index 00000000000..9ceffc816e6
--- /dev/null
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -0,0 +1,281 @@
+// 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.
+
+#include
+
+#include "src/StatsLogProcessor.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+namespace {
+
+StatsdConfig CreateStatsdConfigForPushedEvent(const GaugeMetric::SamplingType sampling_type) {
+ StatsdConfig config;
+ *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+
+ auto atomMatcher = CreateSimpleAtomMatcher("", android::util::APP_START_CHANGED);
+ *config.add_atom_matcher() = atomMatcher;
+
+ auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+ *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
+ *config.add_predicate() = isInBackgroundPredicate;
+
+ auto gaugeMetric = config.add_gauge_metric();
+ gaugeMetric->set_id(123456);
+ gaugeMetric->set_what(atomMatcher.id());
+ gaugeMetric->set_condition(isInBackgroundPredicate.id());
+ gaugeMetric->mutable_gauge_fields_filter()->set_include_all(false);
+ gaugeMetric->set_sampling_type(sampling_type);
+ auto fieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields();
+ fieldMatcher->set_field(android::util::APP_START_CHANGED);
+ fieldMatcher->add_child()->set_field(3); // type (enum)
+ fieldMatcher->add_child()->set_field(4); // activity_name(str)
+ fieldMatcher->add_child()->set_field(7); // activity_start_msec(int64)
+ *gaugeMetric->mutable_dimensions_in_what() =
+ CreateDimensions(android::util::APP_START_CHANGED, {1 /* uid field */ });
+ gaugeMetric->set_bucket(FIVE_MINUTES);
+
+ auto links = gaugeMetric->add_links();
+ links->set_condition(isInBackgroundPredicate.id());
+ auto dimensionWhat = links->mutable_fields_in_what();
+ dimensionWhat->set_field(android::util::APP_START_CHANGED);
+ dimensionWhat->add_child()->set_field(1); // uid field.
+ auto dimensionCondition = links->mutable_fields_in_condition();
+ dimensionCondition->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+ dimensionCondition->add_child()->set_field(1); // uid field.
+ return config;
+}
+
+std::unique_ptr CreateAppStartChangedEvent(
+ const int uid, const string& pkg_name, AppStartChanged::TransitionType type,
+ const string& activity_name, const string& calling_pkg_name, const bool is_instant_app,
+ int64_t activity_start_msec, uint64_t timestampNs) {
+ auto logEvent = std::make_unique(
+ android::util::APP_START_CHANGED, timestampNs);
+ logEvent->write(uid);
+ logEvent->write(pkg_name);
+ logEvent->write(type);
+ logEvent->write(activity_name);
+ logEvent->write(calling_pkg_name);
+ logEvent->write(is_instant_app);
+ logEvent->write(activity_start_msec);
+ logEvent->init();
+ return logEvent;
+}
+
+} // namespace
+
+TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
+ for (const auto& sampling_type :
+ { GaugeMetric::ALL_CONDITION_CHANGES, GaugeMetric:: RANDOM_ONE_SAMPLE }) {
+ auto config = CreateStatsdConfigForPushedEvent(sampling_type);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ int appUid1 = 123;
+ int appUid2 = 456;
+ std::vector> events;
+ events.push_back(CreateMoveToBackgroundEvent(appUid1, bucketStartTimeNs + 15));
+ events.push_back(CreateMoveToForegroundEvent(
+ appUid1, bucketStartTimeNs + bucketSizeNs + 250));
+ events.push_back(CreateMoveToBackgroundEvent(
+ appUid1, bucketStartTimeNs + bucketSizeNs + 350));
+ events.push_back(CreateMoveToForegroundEvent(
+ appUid1, bucketStartTimeNs + 2 * bucketSizeNs + 100));
+
+
+ events.push_back(CreateAppStartChangedEvent(
+ appUid1, "app1", AppStartChanged::WARM, "activity_name1", "calling_pkg_name1",
+ true /*is_instant_app*/, 101 /*activity_start_msec*/, bucketStartTimeNs + 10));
+ events.push_back(CreateAppStartChangedEvent(
+ appUid1, "app1", AppStartChanged::HOT, "activity_name2", "calling_pkg_name2",
+ true /*is_instant_app*/, 102 /*activity_start_msec*/, bucketStartTimeNs + 20));
+ events.push_back(CreateAppStartChangedEvent(
+ appUid1, "app1", AppStartChanged::COLD, "activity_name3", "calling_pkg_name3",
+ true /*is_instant_app*/, 103 /*activity_start_msec*/, bucketStartTimeNs + 30));
+ events.push_back(CreateAppStartChangedEvent(
+ appUid1, "app1", AppStartChanged::WARM, "activity_name4", "calling_pkg_name4",
+ true /*is_instant_app*/, 104 /*activity_start_msec*/,
+ bucketStartTimeNs + bucketSizeNs + 30));
+ events.push_back(CreateAppStartChangedEvent(
+ appUid1, "app1", AppStartChanged::COLD, "activity_name5", "calling_pkg_name5",
+ true /*is_instant_app*/, 105 /*activity_start_msec*/,
+ bucketStartTimeNs + 2 * bucketSizeNs));
+ events.push_back(CreateAppStartChangedEvent(
+ appUid1, "app1", AppStartChanged::HOT, "activity_name6", "calling_pkg_name6",
+ false /*is_instant_app*/, 106 /*activity_start_msec*/,
+ bucketStartTimeNs + 2 * bucketSizeNs + 10));
+
+ events.push_back(CreateMoveToBackgroundEvent(
+ appUid2, bucketStartTimeNs + bucketSizeNs + 10));
+ events.push_back(CreateAppStartChangedEvent(
+ appUid2, "app2", AppStartChanged::COLD, "activity_name7", "calling_pkg_name7",
+ true /*is_instant_app*/, 201 /*activity_start_msec*/,
+ bucketStartTimeNs + 2 * bucketSizeNs + 10));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(
+ reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ EXPECT_EQ(2, gaugeMetrics.data_size());
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(android::util::APP_START_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(3, data.bucket_info_size());
+ if (sampling_type == GaugeMetric::ALL_CONDITION_CHANGES) {
+ EXPECT_EQ(2, data.bucket_info(0).atom_size());
+ EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(2, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_nanos());
+ EXPECT_EQ(AppStartChanged::HOT, data.bucket_info(0).atom(0).app_start_changed().type());
+ EXPECT_EQ("activity_name2",
+ data.bucket_info(0).atom(0).app_start_changed().activity_name());
+ EXPECT_EQ(102L,
+ data.bucket_info(0).atom(0).app_start_changed().activity_start_millis());
+ EXPECT_EQ(AppStartChanged::COLD,
+ data.bucket_info(0).atom(1).app_start_changed().type());
+ EXPECT_EQ("activity_name3",
+ data.bucket_info(0).atom(1).app_start_changed().activity_name());
+ EXPECT_EQ(103L,
+ data.bucket_info(0).atom(1).app_start_changed().activity_start_millis());
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(1).start_bucket_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(1).end_bucket_nanos());
+ EXPECT_EQ(AppStartChanged::WARM,
+ data.bucket_info(1).atom(0).app_start_changed().type());
+ EXPECT_EQ("activity_name4",
+ data.bucket_info(1).atom(0).app_start_changed().activity_name());
+ EXPECT_EQ(104L,
+ data.bucket_info(1).atom(0).app_start_changed().activity_start_millis());
+
+ EXPECT_EQ(2, data.bucket_info(2).atom_size());
+ EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(2, data.bucket_info(2).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(2).start_bucket_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(2).end_bucket_nanos());
+ EXPECT_EQ(AppStartChanged::COLD,
+ data.bucket_info(2).atom(0).app_start_changed().type());
+ EXPECT_EQ("activity_name5",
+ data.bucket_info(2).atom(0).app_start_changed().activity_name());
+ EXPECT_EQ(105L,
+ data.bucket_info(2).atom(0).app_start_changed().activity_start_millis());
+ EXPECT_EQ(AppStartChanged::HOT,
+ data.bucket_info(2).atom(1).app_start_changed().type());
+ EXPECT_EQ("activity_name6",
+ data.bucket_info(2).atom(1).app_start_changed().activity_name());
+ EXPECT_EQ(106L,
+ data.bucket_info(2).atom(1).app_start_changed().activity_start_millis());
+ } else {
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_nanos());
+ EXPECT_EQ(AppStartChanged::HOT, data.bucket_info(0).atom(0).app_start_changed().type());
+ EXPECT_EQ("activity_name2",
+ data.bucket_info(0).atom(0).app_start_changed().activity_name());
+ EXPECT_EQ(102L,
+ data.bucket_info(0).atom(0).app_start_changed().activity_start_millis());
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(1).start_bucket_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(1).end_bucket_nanos());
+ EXPECT_EQ(AppStartChanged::WARM,
+ data.bucket_info(1).atom(0).app_start_changed().type());
+ EXPECT_EQ("activity_name4",
+ data.bucket_info(1).atom(0).app_start_changed().activity_name());
+ EXPECT_EQ(104L,
+ data.bucket_info(1).atom(0).app_start_changed().activity_start_millis());
+
+ EXPECT_EQ(1, data.bucket_info(2).atom_size());
+ EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(1, data.bucket_info(2).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(2).start_bucket_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(2).end_bucket_nanos());
+ EXPECT_EQ(AppStartChanged::COLD,
+ data.bucket_info(2).atom(0).app_start_changed().type());
+ EXPECT_EQ("activity_name5",
+ data.bucket_info(2).atom(0).app_start_changed().activity_name());
+ EXPECT_EQ(105L,
+ data.bucket_info(2).atom(0).app_start_changed().activity_start_millis());
+ }
+
+ data = gaugeMetrics.data(1);
+
+ EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_nanos());
+ EXPECT_EQ(AppStartChanged::COLD, data.bucket_info(0).atom(0).app_start_changed().type());
+ EXPECT_EQ("activity_name7",
+ data.bucket_info(0).atom(0).app_start_changed().activity_name());
+ EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_changed().activity_start_millis());
+ }
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
deleted file mode 100644
index 3843e0a3c67..00000000000
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-// 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.
-
-#include
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-#include
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-StatsdConfig CreateStatsdConfigForPushedEvent() {
- StatsdConfig config;
- *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
- *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-
- auto atomMatcher = CreateSimpleAtomMatcher("", android::util::APP_START_CHANGED);
- *config.add_atom_matcher() = atomMatcher;
-
- auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
- *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
- CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
- *config.add_predicate() = isInBackgroundPredicate;
-
- auto gaugeMetric = config.add_gauge_metric();
- gaugeMetric->set_id(123456);
- gaugeMetric->set_what(atomMatcher.id());
- gaugeMetric->set_condition(isInBackgroundPredicate.id());
- gaugeMetric->mutable_gauge_fields_filter()->set_include_all(false);
- auto fieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields();
- fieldMatcher->set_field(android::util::APP_START_CHANGED);
- fieldMatcher->add_child()->set_field(3); // type (enum)
- fieldMatcher->add_child()->set_field(4); // activity_name(str)
- fieldMatcher->add_child()->set_field(7); // activity_start_msec(int64)
- *gaugeMetric->mutable_dimensions_in_what() =
- CreateDimensions(android::util::APP_START_CHANGED, {1 /* uid field */ });
- gaugeMetric->set_bucket(FIVE_MINUTES);
-
- auto links = gaugeMetric->add_links();
- links->set_condition(isInBackgroundPredicate.id());
- auto dimensionWhat = links->mutable_fields_in_what();
- dimensionWhat->set_field(android::util::APP_START_CHANGED);
- dimensionWhat->add_child()->set_field(1); // uid field.
- auto dimensionCondition = links->mutable_fields_in_condition();
- dimensionCondition->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
- dimensionCondition->add_child()->set_field(1); // uid field.
- return config;
-}
-
-std::unique_ptr CreateAppStartChangedEvent(
- const int uid, const string& pkg_name, AppStartChanged::TransitionType type,
- const string& activity_name, const string& calling_pkg_name, const bool is_instant_app,
- int64_t activity_start_msec, uint64_t timestampNs) {
- auto logEvent = std::make_unique(
- android::util::APP_START_CHANGED, timestampNs);
- logEvent->write(uid);
- logEvent->write(pkg_name);
- logEvent->write(type);
- logEvent->write(activity_name);
- logEvent->write(calling_pkg_name);
- logEvent->write(is_instant_app);
- logEvent->write(activity_start_msec);
- logEvent->init();
- return logEvent;
-}
-
-} // namespace
-
-TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
- auto config = CreateStatsdConfigForPushedEvent();
- int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-
- ConfigKey cfgKey;
- auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
- int appUid1 = 123;
- int appUid2 = 456;
- std::vector> events;
- events.push_back(CreateMoveToBackgroundEvent(appUid1, bucketStartTimeNs + 15));
- events.push_back(CreateMoveToForegroundEvent(appUid1, bucketStartTimeNs + bucketSizeNs + 250));
- events.push_back(CreateMoveToBackgroundEvent(appUid1, bucketStartTimeNs + bucketSizeNs + 350));
- events.push_back(CreateMoveToForegroundEvent(
- appUid1, bucketStartTimeNs + 2 * bucketSizeNs + 100));
-
-
- events.push_back(CreateAppStartChangedEvent(
- appUid1, "app1", AppStartChanged::WARM, "activity_name1", "calling_pkg_name1",
- true /*is_instant_app*/, 101 /*activity_start_msec*/, bucketStartTimeNs + 10));
- events.push_back(CreateAppStartChangedEvent(
- appUid1, "app1", AppStartChanged::HOT, "activity_name2", "calling_pkg_name2",
- true /*is_instant_app*/, 102 /*activity_start_msec*/, bucketStartTimeNs + 20));
- events.push_back(CreateAppStartChangedEvent(
- appUid1, "app1", AppStartChanged::COLD, "activity_name3", "calling_pkg_name3",
- true /*is_instant_app*/, 103 /*activity_start_msec*/, bucketStartTimeNs + 30));
- events.push_back(CreateAppStartChangedEvent(
- appUid1, "app1", AppStartChanged::WARM, "activity_name4", "calling_pkg_name4",
- true /*is_instant_app*/, 104 /*activity_start_msec*/,
- bucketStartTimeNs + bucketSizeNs + 30));
- events.push_back(CreateAppStartChangedEvent(
- appUid1, "app1", AppStartChanged::COLD, "activity_name5", "calling_pkg_name5",
- true /*is_instant_app*/, 105 /*activity_start_msec*/,
- bucketStartTimeNs + 2 * bucketSizeNs));
- events.push_back(CreateAppStartChangedEvent(
- appUid1, "app1", AppStartChanged::HOT, "activity_name6", "calling_pkg_name6",
- false /*is_instant_app*/, 106 /*activity_start_msec*/,
- bucketStartTimeNs + 2 * bucketSizeNs + 10));
-
- events.push_back(CreateMoveToBackgroundEvent(appUid2, bucketStartTimeNs + bucketSizeNs + 10));
- events.push_back(CreateAppStartChangedEvent(
- appUid2, "app2", AppStartChanged::COLD, "activity_name7", "calling_pkg_name7",
- true /*is_instant_app*/, 201 /*activity_start_msec*/,
- bucketStartTimeNs + 2 * bucketSizeNs + 10));
-
- sortLogEventsByTimestamp(&events);
-
- for (const auto& event : events) {
- processor->OnLogEvent(event.get());
- }
- ConfigMetricsReportList reports;
- vector buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, &buffer);
- EXPECT_TRUE(buffer.size() > 0);
- EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
- EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
- sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
- EXPECT_EQ(gaugeMetrics.data_size(), 2);
-
- auto data = gaugeMetrics.data(0);
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1 /* uid field */);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid1);
- EXPECT_EQ(data.bucket_info_size(), 3);
- EXPECT_EQ(data.bucket_info(0).atom_size(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().type(), AppStartChanged::HOT);
- EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_name(), "activity_name2");
- EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_millis(), 102L);
-
- EXPECT_EQ(data.bucket_info(1).atom_size(), 1);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().type(), AppStartChanged::WARM);
- EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_name(), "activity_name4");
- EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_start_millis(), 104L);
-
- EXPECT_EQ(data.bucket_info(2).atom_size(), 1);
- EXPECT_EQ(data.bucket_info(2).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
- EXPECT_EQ(data.bucket_info(2).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
- EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().type(), AppStartChanged::COLD);
- EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_name(), "activity_name5");
- EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_start_millis(), 105L);
-
- data = gaugeMetrics.data(1);
-
- EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_CHANGED);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1 /* uid field */);
- EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid2);
- EXPECT_EQ(data.bucket_info_size(), 1);
- EXPECT_EQ(data.bucket_info(0).atom_size(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().type(), AppStartChanged::COLD);
- EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_name(), "activity_name7");
- EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_millis(), 201L);
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-} // namespace statsd
-} // namespace os
-} // namespace android
--
GitLab
From 090c6b1c94f75fb0d2193354ca453d528da0fa99 Mon Sep 17 00:00:00 2001
From: Jiyong Park
Date: Thu, 28 Dec 2017 12:03:28 +0900
Subject: [PATCH 050/488] Allow apps in /odm/app and /odm/priv-app
/odm is a vendor partition other than /vendor. Both partitions are for
HW-specific modules such as HALs. The difference is that /odm is owned
by ODM (usually device manufacturer which designs the board), whereas
/vendor is owned by SoC manufacturer. In other words, /odm partition is
for board-specific customization to the /vendor partition.
Since apps can exist in /vendor/app and /vendor/priv-app, the same has
to be supported for /odm partition.
Bug: 71366495
Test: m -j
Teet: cd frameworks/base/tests/OdmApps; atest .
Change-Id: I1ec8b22b080efdefd67a45ce9c7aeaa2aef350e0
---
.../java/com/android/server/SystemConfig.java | 9 +++--
.../server/pm/PackageManagerService.java | 38 ++++++++++++++++++-
tests/OdmApps/Android.mk | 26 +++++++++++++
tests/OdmApps/AndroidTest.xml | 27 +++++++++++++
tests/OdmApps/app/Android.mk | 22 +++++++++++
tests/OdmApps/app/AndroidManifest.xml | 21 ++++++++++
tests/OdmApps/priv-app/Android.mk | 22 +++++++++++
tests/OdmApps/priv-app/AndroidManifest.xml | 21 ++++++++++
.../com/android/test/odm/app/OdmAppsTest.java | 35 +++++++++++++++++
9 files changed, 216 insertions(+), 5 deletions(-)
create mode 100644 tests/OdmApps/Android.mk
create mode 100644 tests/OdmApps/AndroidTest.xml
create mode 100644 tests/OdmApps/app/Android.mk
create mode 100755 tests/OdmApps/app/AndroidManifest.xml
create mode 100644 tests/OdmApps/priv-app/Android.mk
create mode 100755 tests/OdmApps/priv-app/AndroidManifest.xml
create mode 100644 tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 8b1de2fb886..9d4b5aa9fc7 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -284,8 +284,9 @@ public class SystemConfig {
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
- // Allow ODM to customize system configs around libs, features and apps
- int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
+ // Allow ODM to customize system configs as much as Vendor, because /odm is another
+ // vendor partition other than /vendor.
+ int odmPermissionFlag = vendorPermissionFlag;
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
readPermissions(Environment.buildPath(
@@ -631,7 +632,9 @@ public class SystemConfig {
// granting permissions to priv apps in the system partition and vice
// versa.
boolean vendor = permFile.toPath().startsWith(
- Environment.getVendorDirectory().toPath());
+ Environment.getVendorDirectory().toPath())
+ || permFile.toPath().startsWith(
+ Environment.getOdmDirectory().toPath());
boolean product = permFile.toPath().startsWith(
Environment.getProductDirectory().toPath());
if (vendor) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f12795be658..eb9fe9cbd39 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2592,7 +2592,7 @@ public class PackageManagerService extends IPackageManager.Stub
| SCAN_AS_PRIVILEGED,
0);
- // Collected privileged system packages.
+ // Collect privileged system packages.
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
scanDirTracedLI(privilegedAppDir,
mDefParseFlags
@@ -2611,7 +2611,7 @@ public class PackageManagerService extends IPackageManager.Stub
| SCAN_AS_SYSTEM,
0);
- // Collected privileged vendor packages.
+ // Collect privileged vendor packages.
File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
try {
privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile();
@@ -2642,6 +2642,40 @@ public class PackageManagerService extends IPackageManager.Stub
| SCAN_AS_VENDOR,
0);
+ // Collect privileged odm packages. /odm is another vendor partition
+ // other than /vendor.
+ File privilegedOdmAppDir = new File(Environment.getOdmDirectory(),
+ "priv-app");
+ try {
+ privilegedOdmAppDir = privilegedOdmAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
+ scanDirTracedLI(privilegedOdmAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR
+ | SCAN_AS_PRIVILEGED,
+ 0);
+
+ // Collect ordinary odm packages. /odm is another vendor partition
+ // other than /vendor.
+ File odmAppDir = new File(Environment.getOdmDirectory(), "app");
+ try {
+ odmAppDir = odmAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
+ scanDirTracedLI(odmAppDir,
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_VENDOR,
+ 0);
+
// Collect all OEM packages.
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirTracedLI(oemAppDir,
diff --git a/tests/OdmApps/Android.mk b/tests/OdmApps/Android.mk
new file mode 100644
index 00000000000..64fa65325ac
--- /dev/null
+++ b/tests/OdmApps/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := OdmAppsTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_JAVA_LIBRARIES := tradefed
+LOCAL_COMPATIBILITY_SUITE := device-tests
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/OdmApps/AndroidTest.xml b/tests/OdmApps/AndroidTest.xml
new file mode 100644
index 00000000000..2f1283850a9
--- /dev/null
+++ b/tests/OdmApps/AndroidTest.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/OdmApps/app/Android.mk b/tests/OdmApps/app/Android.mk
new file mode 100644
index 00000000000..9eec0cc4f66
--- /dev/null
+++ b/tests/OdmApps/app/Android.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := TestOdmApp
+LOCAL_MODULE_TAGS := tests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_SDK_VERSION := current
+include $(BUILD_PACKAGE)
diff --git a/tests/OdmApps/app/AndroidManifest.xml b/tests/OdmApps/app/AndroidManifest.xml
new file mode 100755
index 00000000000..84a9ea84b52
--- /dev/null
+++ b/tests/OdmApps/app/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/tests/OdmApps/priv-app/Android.mk b/tests/OdmApps/priv-app/Android.mk
new file mode 100644
index 00000000000..d423133fc9f
--- /dev/null
+++ b/tests/OdmApps/priv-app/Android.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := TestOdmPrivApp
+LOCAL_MODULE_TAGS := tests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_SDK_VERSION := current
+include $(BUILD_PACKAGE)
diff --git a/tests/OdmApps/priv-app/AndroidManifest.xml b/tests/OdmApps/priv-app/AndroidManifest.xml
new file mode 100755
index 00000000000..031cf64ea7b
--- /dev/null
+++ b/tests/OdmApps/priv-app/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java b/tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java
new file mode 100644
index 00000000000..de742b80a37
--- /dev/null
+++ b/tests/OdmApps/src/com/android/test/odm/app/OdmAppsTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.odm.apps;
+
+import com.android.tradefed.testtype.DeviceTestCase;
+
+public class OdmAppsTest extends DeviceTestCase {
+ /**
+ * Test if /odm/app is working
+ */
+ public void testOdmApp() throws Exception {
+ assertNotNull(getDevice().getAppPackageInfo("com.android.test.odm.app"));
+ }
+
+ /**
+ * Test if /odm/priv-app is working
+ */
+ public void testOdmPrivApp() throws Exception {
+ assertNotNull(getDevice().getAppPackageInfo("com.android.test.odm.privapp"));
+ }
+}
--
GitLab
From fad9944e7eea8da58cfca52c1f2aa76c34612bd7 Mon Sep 17 00:00:00 2001
From: Jiyong Park
Date: Mon, 12 Mar 2018 10:39:07 +0900
Subject: [PATCH 051/488] Limit the systemconfig tags allowed to vendors
Vendors are allowed to customize these systemconfig tags only.
This is because the systemconfig tags are essentially the part of system
<-> vendor interface and thus need to be stable (or evolve in a backward
compatible manner) across several Android releases and we would like to
keep the interface as small as as possible.
However, since vendors were allowed to use more tags (like ,
, ) in Oreo and Oreo-MR1, this
limitation is applied only for newly launching devices whose first API
level is equal to or greater than P.
Bug: 70821981
Test: wahoo is bootable (launched with Oreo)
Test: crosshatch is bootable (launched with P)
Test: adb logcat -s SystemConfig does not show that a tag is not
supported
Change-Id: I371b93a80f3d9728ea6d35022081776a8658d9f3
---
core/java/com/android/server/SystemConfig.java | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 8b1de2fb886..a652a9a4dc9 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -22,6 +22,7 @@ import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.Environment;
import android.os.Process;
import android.os.storage.StorageManager;
@@ -276,9 +277,12 @@ public class SystemConfig {
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
- // Allow Vendor to customize system configs around libs, features, permissions and apps
- int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
- ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS;
+ // Vendors are only allowed to customze libs, features and privapp permissions
+ int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS;
+ if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) {
+ // For backward compatibility
+ vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
+ }
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
readPermissions(Environment.buildPath(
@@ -656,6 +660,8 @@ public class SystemConfig {
}
XmlUtils.skipCurrentTag(parser);
} else {
+ Slog.w(TAG, "Tag " + name + " is unknown or not allowed in "
+ + permFile.getParent());
XmlUtils.skipCurrentTag(parser);
continue;
}
--
GitLab
From 94bc48f7bbff4772de967bcfc3effd4f710503c2 Mon Sep 17 00:00:00 2001
From: Chalard Jean
Date: Fri, 9 Mar 2018 22:28:51 +0900
Subject: [PATCH 052/488] Add the ability to refresh to the captive portal app.
Bug: 69840796
Test: manual
created a small app that brings up the captive portal app,
checked that pulling down does show the refresh spinner,
refresh the page, and hide the spinner when refreshed.
Checked that it works multiple times in a row.
Change-Id: Ieefdaffa9325b0c5f1b02ab6052c29a381f3a4d4
---
packages/CaptivePortalLogin/Android.mk | 1 +
.../layout/activity_captive_portal_login.xml | 17 +++++++++++------
.../CaptivePortalLoginActivity.java | 10 ++++++++++
3 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/packages/CaptivePortalLogin/Android.mk b/packages/CaptivePortalLogin/Android.mk
index e6e0ad33c80..7dc23ff8e8b 100644
--- a/packages/CaptivePortalLogin/Android.mk
+++ b/packages/CaptivePortalLogin/Android.mk
@@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml b/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
index 232459338f4..c292323b60c 100644
--- a/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
+++ b/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
@@ -27,12 +27,17 @@
android:layout_height="wrap_content" />
-
+
+
+
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index e13aba7e5fe..4db00345fc8 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -34,6 +34,7 @@ import android.net.http.SslError;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
+import android.support.v4.widget.SwipeRefreshLayout;
import android.util.ArrayMap;
import android.util.Log;
import android.util.TypedValue;
@@ -88,6 +89,7 @@ public class CaptivePortalLoginActivity extends Activity {
private ConnectivityManager mCm;
private boolean mLaunchBrowser = false;
private MyWebViewClient mWebViewClient;
+ private SwipeRefreshLayout mSwipeRefreshLayout;
// Ensures that done() happens once exactly, handling concurrent callers with atomic operations.
private final AtomicBoolean isDone = new AtomicBoolean(false);
@@ -159,6 +161,13 @@ public class CaptivePortalLoginActivity extends Activity {
// Start initial page load so WebView finishes loading proxy settings.
// Actual load of mUrl is initiated by MyWebViewClient.
webview.loadData("", "text/html", null);
+
+ mSwipeRefreshLayout = findViewById(R.id.swipe_refresh);
+ mSwipeRefreshLayout.setOnRefreshListener(() -> {
+ webview.reload();
+ mSwipeRefreshLayout.setRefreshing(true);
+ });
+
}
// Find WebView's proxy BroadcastReceiver and prompt it to read proxy system properties.
@@ -393,6 +402,7 @@ public class CaptivePortalLoginActivity extends Activity {
public void onPageFinished(WebView view, String url) {
mPagesLoaded++;
getProgressBar().setVisibility(View.INVISIBLE);
+ mSwipeRefreshLayout.setRefreshing(false);
if (mPagesLoaded == 1) {
// Now that WebView has loaded at least one page we know it has read in the proxy
// settings. Now prompt the WebView read the Network-specific proxy settings.
--
GitLab
From 3662b155f681a44b5fc5f96122246104c981c164 Mon Sep 17 00:00:00 2001
From: Benjamin Franz
Date: Tue, 16 Jan 2018 17:23:44 +0000
Subject: [PATCH 053/488] Disable immersive mode confirmation when device is in
lock task mode
Bug: 68305547
Test: manual, with DEBUG_SHOW_EVERY_TIME
Change-Id: I42fa1ed771a8216304a0ba7330cd842ae23e8a03
---
.../android/server/am/LockTaskController.java | 2 ++
.../server/policy/ImmersiveModeConfirmation.java | 11 ++++++++++-
.../server/policy/PhoneWindowManager.java | 5 +++++
.../server/policy/WindowManagerPolicy.java | 12 ++++++++++++
.../android/server/wm/WindowManagerService.java | 16 +++++++++++++++-
.../server/wm/TestWindowManagerPolicy.java | 4 ++++
6 files changed, 48 insertions(+), 2 deletions(-)
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index af99111e4bf..ed39329844e 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -469,6 +469,7 @@ public class LockTaskController {
if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
getStatusBarService().showPinningEnterExitToast(false /* entering */);
}
+ mWindowManager.onLockTaskStateChanged(LOCK_TASK_MODE_NONE);
} catch (RemoteException ex) {
throw new RuntimeException(ex);
} finally {
@@ -580,6 +581,7 @@ public class LockTaskController {
if (lockTaskModeState == LOCK_TASK_MODE_PINNED) {
getStatusBarService().showPinningEnterExitToast(true /* entering */);
}
+ mWindowManager.onLockTaskStateChanged(lockTaskModeState);
mLockTaskModeState = lockTaskModeState;
setStatusBarState(lockTaskModeState, userId);
setKeyguardState(lockTaskModeState, userId);
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index c6ec287d9c6..4aa24465215 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -16,6 +16,9 @@
package com.android.server.policy;
+import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
+import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
@@ -78,6 +81,7 @@ public class ImmersiveModeConfirmation {
// Local copy of vr mode enabled state, to avoid calling into VrManager with
// the lock held.
boolean mVrModeEnabled = false;
+ private int mLockTaskState = LOCK_TASK_MODE_NONE;
public ImmersiveModeConfirmation(Context context) {
mContext = ActivityThread.currentActivityThread().getSystemUiContext();
@@ -148,7 +152,8 @@ public class ImmersiveModeConfirmation {
&& userSetupComplete
&& !mVrModeEnabled
&& !navBarEmpty
- && !UserManager.isDeviceInDemoMode(mContext)) {
+ && !UserManager.isDeviceInDemoMode(mContext)
+ && (mLockTaskState != LOCK_TASK_MODE_LOCKED)) {
mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
}
} else {
@@ -401,4 +406,8 @@ public class ImmersiveModeConfirmation {
}
}
};
+
+ void onLockTaskModeChangedLw(int lockTaskState) {
+ mLockTaskState = lockTaskState;
+ }
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 87be0a21d7d..bb28f2b9cd2 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -8786,4 +8786,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return Integer.toString(behavior);
}
}
+
+ @Override
+ public void onLockTaskStateChangedLw(int lockTaskState) {
+ mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
+ }
}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 9bd508e6020..8dfaac2c3c4 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -66,6 +66,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.CompatibilityInfo;
@@ -1730,4 +1731,15 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
* on the next user activity.
*/
public void requestUserActivityNotification();
+
+ /**
+ * Called when the state of lock task mode changes. This should be used to disable immersive
+ * mode confirmation.
+ *
+ * @param lockTaskState the new lock task mode state. One of
+ * {@link ActivityManager#LOCK_TASK_MODE_NONE},
+ * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
+ * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
+ */
+ void onLockTaskStateChangedLw(int lockTaskState);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1ded81d0351..98e6bf9e319 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7436,5 +7436,19 @@ public class WindowManagerService extends IWindowManager.Stub
mH.obtainMessage(H.SET_RUNNING_REMOTE_ANIMATION, pid, runningRemoteAnimation ? 1 : 0)
.sendToTarget();
}
-}
+ /**
+ * Called when the state of lock task mode changes. This should be used to disable immersive
+ * mode confirmation.
+ *
+ * @param lockTaskState the new lock task mode state. One of
+ * {@link ActivityManager#LOCK_TASK_MODE_NONE},
+ * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
+ * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
+ */
+ public void onLockTaskStateChanged(int lockTaskState) {
+ synchronized (mWindowMap) {
+ mPolicy.onLockTaskStateChangedLw(lockTaskState);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 6784e302a5c..6d9167fda58 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -656,4 +656,8 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
@Override
public void requestUserActivityNotification() {
}
+
+ @Override
+ public void onLockTaskStateChangedLw(int lockTaskState) {
+ }
}
--
GitLab
From 0f41a7cf825edfc617e6334f02907bea6efd1179 Mon Sep 17 00:00:00 2001
From: David Brazdil
Date: Mon, 12 Mar 2018 10:15:46 +0000
Subject: [PATCH 054/488] Add hidden API used by CTS to greylist
Hidden API uses detected during a run of CTS.
Bug: 64382372
Test: make
Test: run CTS, no 'dark greylist' uses
Change-Id: I7e1d4ddc731d35e427e2781f0a867db68c5f45ec
---
config/hiddenapi-light-greylist.txt | 119 ++++++++++++++++++++++++++++
1 file changed, 119 insertions(+)
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 1a1d431b1d2..8d5a9ec0cd8 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -16,6 +16,7 @@ Landroid/app/ActivityManager;->isUserRunning(I)Z
Landroid/app/ActivityManager;->mContext:Landroid/content/Context;
Landroid/app/ActivityManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
+Landroid/app/ActivityManager;->PROCESS_STATE_IMPORTANT_BACKGROUND:I
Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I
Landroid/app/ActivityManager$RecentTaskInfo;->firstActiveTime:J
Landroid/app/ActivityManager$RunningAppProcessInfo;->flags:I
@@ -114,6 +115,7 @@ Landroid/app/admin/DevicePolicyManager;->getTrustAgentConfiguration(Landroid/con
Landroid/app/admin/DevicePolicyManager;->packageHasActiveAdmins(Ljava/lang/String;I)Z
Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V
Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;Z)V
+Landroid/app/admin/DevicePolicyManager;->throwIfParentInstance(Ljava/lang/String;)V
Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I
Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I
Landroid/app/admin/SecurityLog$SecurityEvent;->([B)V
@@ -337,6 +339,7 @@ Landroid/bluetooth/IBluetooth;->getAddress()Ljava/lang/String;
Landroid/bluetooth/IBluetoothManager$Stub$Proxy;->(Landroid/os/IBinder;)V
Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth;
Landroid/bluetooth/IBluetooth$Stub$Proxy;->getAddress()Ljava/lang/String;
+Landroid/bluetooth/le/ScanRecord;->parseFromBytes([B)Landroid/bluetooth/le/ScanRecord;
Landroid/content/AsyncTaskLoader;->mExecutor:Ljava/util/concurrent/Executor;
Landroid/content/BroadcastReceiver$PendingResult;->(ILjava/lang/String;Landroid/os/Bundle;IZZLandroid/os/IBinder;II)V
Landroid/content/BroadcastReceiver;->setPendingResult(Landroid/content/BroadcastReceiver$PendingResult;)V
@@ -443,6 +446,7 @@ Landroid/content/pm/PackageParser$ServiceIntentInfo;->service:Landroid/content/p
Landroid/content/pm/PackageUserState;->()V
Landroid/content/pm/ParceledListSlice;->(Ljava/util/List;)V
Landroid/content/pm/ResolveInfo;->instantAppAvailable:Z
+Landroid/content/pm/ShortcutManager;->mService:Landroid/content/pm/IShortcutService;
Landroid/content/pm/Signature;->getPublicKey()Ljava/security/PublicKey;
Landroid/content/pm/UserInfo;->id:I
Landroid/content/pm/UserInfo;->isPrimary()Z
@@ -683,15 +687,24 @@ Landroid/hardware/usb/IUsbManager$Stub$Proxy;->(Landroid/os/IBinder;)V
Landroid/hardware/usb/UsbDeviceConnection;->mNativeContext:J
Landroid/hardware/usb/UsbManager;->setCurrentFunction(Ljava/lang/String;Z)V
Landroid/hardware/usb/UsbRequest;->mNativeContext:J
+Landroid/icu/impl/CurrencyData;->()V
Landroid/icu/impl/number/DecimalFormatProperties;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/impl/number/DecimalFormatProperties;->writeObject(Ljava/io/ObjectOutputStream;)V
Landroid/icu/impl/TimeZoneGenericNames;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/ArabicShaping;->isAlefMaksouraChar(C)Z
+Landroid/icu/text/ArabicShaping;->isSeenTailFamilyChar(C)I
+Landroid/icu/text/ArabicShaping;->isTailChar(C)Z
+Landroid/icu/text/ArabicShaping;->isYehHamzaChar(C)Z
Landroid/icu/text/DateFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
Landroid/icu/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateIntervalFormat;->()V
Landroid/icu/text/DateIntervalFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateTimePatternGenerator$DistanceInfo;->()V
Landroid/icu/text/DecimalFormat_ICU58_Android;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/DecimalFormat_ICU58_Android;->writeObject(Ljava/io/ObjectOutputStream;)V
Landroid/icu/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DecimalFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
Landroid/icu/text/DecimalFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/DecimalFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
Landroid/icu/text/MessageFormat;->readObject(Ljava/io/ObjectInputStream;)V
@@ -703,13 +716,23 @@ Landroid/icu/text/PluralRules$FixedDecimal;->readObject(Ljava/io/ObjectInputStre
Landroid/icu/text/PluralRules$FixedDecimal;->writeObject(Ljava/io/ObjectOutputStream;)V
Landroid/icu/text/PluralRules;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/PluralRules;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/RuleBasedCollator;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
Landroid/icu/text/RuleBasedNumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/RuleBasedNumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
Landroid/icu/text/SelectFormat;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/SimpleDateFormat;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/SimpleDateFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/SpoofChecker$ScriptSet;->and(I)V
+Landroid/icu/text/SpoofChecker$ScriptSet;->()V
+Landroid/icu/text/SpoofChecker$ScriptSet;->isFull()Z
+Landroid/icu/text/SpoofChecker$ScriptSet;->setAll()V
Landroid/icu/text/TimeZoneFormat;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/text/TimeZoneFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/TimeZoneNames$DefaultTimeZoneNames$FactoryImpl;->()V
+Landroid/icu/text/Transliterator;->createFromRules(Ljava/lang/String;Ljava/lang/String;I)Landroid/icu/text/Transliterator;
+Landroid/icu/text/Transliterator;->transliterate(Ljava/lang/String;)Ljava/lang/String;
+Landroid/icu/text/UFormat;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
+Landroid/icu/util/Calendar;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
Landroid/icu/util/Calendar;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/util/Calendar;->writeObject(Ljava/io/ObjectOutputStream;)V
Landroid/icu/util/ChineseCalendar;->readObject(Ljava/io/ObjectInputStream;)V
@@ -738,6 +761,8 @@ Landroid/media/AudioFormat;->(IIII)V
Landroid/media/AudioFormat;->mChannelMask:I
Landroid/media/AudioFormat;->mEncoding:I
Landroid/media/AudioFormat;->mSampleRate:I
+Landroid/media/audiofx/AudioEffect;->command(I[B[B)I
+Landroid/media/audiofx/AudioEffect;->getParameter([I[B)I
Landroid/media/audiofx/AudioEffect;->(Ljava/util/UUID;Ljava/util/UUID;II)V
Landroid/media/AudioGainConfig;->(ILandroid/media/AudioGain;II[II)V
Landroid/media/AudioGainConfig;->mChannelMask:I
@@ -785,9 +810,12 @@ Landroid/media/AudioPort;->mActiveConfig:Landroid/media/AudioPortConfig;
Landroid/media/AudioPort;->mGains:[Landroid/media/AudioGain;
Landroid/media/AudioPort;->mHandle:Landroid/media/AudioHandle;
Landroid/media/AudioPort;->mRole:I
+Landroid/media/AudioRecordingConfiguration;->getClientPackageName()Ljava/lang/String;
+Landroid/media/AudioRecordingConfiguration;->getClientUid()I
Landroid/media/AudioRecord;->mNativeCallbackCookie:J
Landroid/media/AudioRecord;->mNativeDeviceCallback:J
Landroid/media/AudioRecord;->mNativeRecorderInJavaObj:J
+Landroid/media/AudioRecord;->native_release()V
Landroid/media/AudioRecord;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
Landroid/media/AudioSystem;->dynamicPolicyCallbackFromNative(ILjava/lang/String;I)V
Landroid/media/AudioSystem;->errorCallbackFromNative(I)V
@@ -795,15 +823,18 @@ Landroid/media/AudioSystem;->getPrimaryOutputFrameCount()I
Landroid/media/AudioSystem;->getPrimaryOutputSamplingRate()I
Landroid/media/AudioSystem;->recordingCallbackFromNative(IIII[I)V
Landroid/media/AudioSystem;->setDeviceConnectionState(IILjava/lang/String;Ljava/lang/String;)I
+Landroid/media/AudioTrack;->deferred_connect(J)V
Landroid/media/AudioTrack;->getLatency()I
Landroid/media/AudioTrack;->mJniData:J
Landroid/media/AudioTrack;->mNativeTrackInJavaObj:J
Landroid/media/AudioTrack;->mStreamType:I
+Landroid/media/AudioTrack;->native_release()V
Landroid/media/AudioTrack;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
Landroid/media/IAudioService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IAudioService;
Landroid/media/IAudioService$Stub$Proxy;->(Landroid/os/IBinder;)V
Landroid/media/JetPlayer;->mNativePlayerInJavaObj:J
Landroid/media/JetPlayer;->postEventFromNative(Ljava/lang/Object;III)V
+Landroid/media/MediaCodec$CodecException;->(IILjava/lang/String;)V
Landroid/media/MediaCodec;->releaseOutputBuffer(IZZJ)V
Landroid/media/MediaFile;->FIRST_AUDIO_FILE_TYPE:I
Landroid/media/MediaFile;->getFileType(Ljava/lang/String;)Landroid/media/MediaFile$MediaFileType;
@@ -975,6 +1006,7 @@ Landroid/net/wifi/WifiEnterpriseConfig;->getCaCertificateAlias()Ljava/lang/Strin
Landroid/net/wifi/WifiEnterpriseConfig;->getClientCertificateAlias()Ljava/lang/String;
Landroid/net/wifi/WifiInfo;->getMeteredHint()Z
Landroid/net/wifi/WifiInfo;->mMacAddress:Ljava/lang/String;
+Landroid/net/wifi/WifiInfo;->removeDoubleQuotes(Ljava/lang/String;)Ljava/lang/String;
Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V
Landroid/net/wifi/WifiManager;->connect(ILandroid/net/wifi/WifiManager$ActionListener;)V
Landroid/net/wifi/WifiManager;->forget(ILandroid/net/wifi/WifiManager$ActionListener;)V
@@ -1046,6 +1078,7 @@ Landroid/os/Debug$MemoryInfo;->otherSwappablePss:I
Landroid/os/Debug$MemoryInfo;->otherSwappedOut:I
Landroid/os/Debug$MemoryInfo;->otherSwappedOutPss:I
Landroid/os/Environment;->buildExternalStorageAppDataDirs(Ljava/lang/String;)[Ljava/io/File;
+Landroid/os/Environment;->getVendorDirectory()Ljava/io/File;
Landroid/os/FileObserver$ObserverThread;->onEvent(IILjava/lang/String;)V
Landroid/os/FileUtils;->checksumCrc32(Ljava/io/File;)J
Landroid/os/FileUtils;->copyFile(Ljava/io/File;Ljava/io/File;)Z
@@ -1092,7 +1125,9 @@ Landroid/os/Message;->target:Landroid/os/Handler;
Landroid/os/Message;->when:J
Landroid/os/ParcelFileDescriptor;->(Ljava/io/FileDescriptor;)V
Landroid/os/Parcel;->mNativePtr:J
+Landroid/os/Parcel;->readArrayMap(Landroid/util/ArrayMap;Ljava/lang/ClassLoader;)V
Landroid/os/Parcel$ReadWriteHelper;->()V
+Landroid/os/Parcel;->writeArrayMap(Landroid/util/ArrayMap;)V
Landroid/os/PowerManager;->getMaximumScreenBrightnessSetting()I
Landroid/os/PowerManager;->getMinimumScreenBrightnessSetting()I
Landroid/os/PowerManager;->isLightDeviceIdleMode()Z
@@ -1119,6 +1154,7 @@ Landroid/os/ServiceManager;->listServices()[Ljava/lang/String;
Landroid/os/ServiceManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/os/IServiceManager;
Landroid/os/ServiceManager;->sCache:Ljava/util/HashMap;
Landroid/os/ServiceManager;->sServiceManager:Landroid/os/IServiceManager;
+Landroid/os/SharedMemory;->getFd()I
Landroid/os/storage/DiskInfo;->getDescription()Ljava/lang/String;
Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
Landroid/os/storage/IStorageManager$Stub$Proxy;->(Landroid/os/IBinder;)V
@@ -1183,6 +1219,7 @@ Landroid/os/UserManager;->getMaxSupportedUsers()I
Landroid/os/UserManager;->getProfiles(I)Ljava/util/List;
Landroid/os/UserManager;->getUserHandle()I
Landroid/os/UserManager;->getUserHandle(I)I
+Landroid/os/UserManager;->getUserIcon(I)Landroid/graphics/Bitmap;
Landroid/os/UserManager;->getUserInfo(I)Landroid/content/pm/UserInfo;
Landroid/os/UserManager;->getUserSerialNumber(I)I
Landroid/os/UserManager;->getUsers()Ljava/util/List;
@@ -1192,11 +1229,14 @@ Landroid/os/UserManager;->isUserUnlocked(I)Z
Landroid/os/VintfObject;->report()[Ljava/lang/String;
Landroid/os/WorkSource;->add(ILjava/lang/String;)Z
Landroid/os/WorkSource;->add(I)Z
+Landroid/os/WorkSource;->addReturningNewbs(Landroid/os/WorkSource;)Landroid/os/WorkSource;
Landroid/os/WorkSource;->get(I)I
Landroid/os/WorkSource;->getName(I)Ljava/lang/String;
+Landroid/os/WorkSource;->(I)V
Landroid/os/WorkSource;->mNames:[Ljava/lang/String;
Landroid/os/WorkSource;->mNum:I
Landroid/os/WorkSource;->mUids:[I
+Landroid/os/WorkSource;->setReturningDiffs(Landroid/os/WorkSource;)[Landroid/os/WorkSource;
Landroid/os/WorkSource;->size()I
Landroid/preference/DialogPreference;->mBuilder:Landroid/app/AlertDialog$Builder;
Landroid/preference/DialogPreference;->mDialogIcon:Landroid/graphics/drawable/Drawable;
@@ -1552,6 +1592,7 @@ Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoCount()I
Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoList()Ljava/util/List;
Landroid/telephony/SubscriptionManager;->getDefaultDataSubscriptionInfo()Landroid/telephony/SubscriptionInfo;
Landroid/telephony/SubscriptionManager;->getDefaultSmsPhoneId()I
+Landroid/telephony/SubscriptionManager;->getDefaultVoiceSubscriptionInfo()Landroid/telephony/SubscriptionInfo;
Landroid/telephony/SubscriptionManager;->getPhoneId(I)I
Landroid/telephony/SubscriptionManager;->getSlotIndex(I)I
Landroid/telephony/SubscriptionManager;->getSubId(I)[I
@@ -1652,6 +1693,7 @@ Landroid/text/TextPaint;->setUnderlineText(IF)V
Landroid/transition/ChangeBounds;->BOTTOM_RIGHT_ONLY_PROPERTY:Landroid/util/Property;
Landroid/transition/ChangeBounds;->POSITION_PROPERTY:Landroid/util/Property;
Landroid/transition/TransitionManager;->sRunningTransitions:Ljava/lang/ThreadLocal;
+Landroid/util/ArrayMap;->append(Ljava/lang/Object;Ljava/lang/Object;)V
Landroid/util/ArrayMap;->mBaseCacheSize:I
Landroid/util/ArrayMap;->mTwiceBaseCacheSize:I
Landroid/util/DisplayMetrics;->noncompatHeightPixels:I
@@ -1667,6 +1709,8 @@ Landroid/util/NtpTrustedTime;->getCachedNtpTimeReference()J
Landroid/util/NtpTrustedTime;->getInstance(Landroid/content/Context;)Landroid/util/NtpTrustedTime;
Landroid/util/NtpTrustedTime;->hasCache()Z
Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object;
+Landroid/util/Rational;->mDenominator:I
+Landroid/util/Rational;->mNumerator:I
Landroid/util/Rational;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/util/Singleton;->mInstance:Ljava/lang/Object;
Landroid/util/SparseIntArray;->mKeys:[I
@@ -2162,6 +2206,73 @@ Landroid/widget/VideoView;->mSHCallback:Landroid/view/SurfaceHolder$Callback;
Landroid/widget/VideoView;->mUri:Landroid/net/Uri;
Landroid/widget/VideoView;->mVideoHeight:I
Landroid/widget/VideoView;->mVideoWidth:I
+Lcom/android/ims/internal/uce/common/CapInfo;->()V
+Lcom/android/ims/internal/uce/common/CapInfo;->setCapTimestamp(J)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setCdViaPresenceSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setExts([Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFtHttpSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFtSnFSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFtSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFtThumbSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setFullSnFGroupChatSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setGeoPullFtSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setGeoPullSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setGeoPushSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setImSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setIpVideoSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setIpVoiceSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setIsSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setRcsIpVideoCallSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setRcsIpVideoOnlyCallSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setRcsIpVoiceCallSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setSmSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setSpSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setVsDuringCSSupported(Z)V
+Lcom/android/ims/internal/uce/common/CapInfo;->setVsSupported(Z)V
+Lcom/android/ims/internal/uce/common/StatusCode;->()V
+Lcom/android/ims/internal/uce/common/StatusCode;->setStatusCode(I)V
+Lcom/android/ims/internal/uce/common/UceLong;->getUceLong()J
+Lcom/android/ims/internal/uce/common/UceLong;->setUceLong(J)V
+Lcom/android/ims/internal/uce/presence/PresCmdId;->()V
+Lcom/android/ims/internal/uce/presence/PresCmdId;->setCmdId(I)V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->()V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setCmdId(Lcom/android/ims/internal/uce/presence/PresCmdId;)V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setRequestId(I)V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setStatus(Lcom/android/ims/internal/uce/common/StatusCode;)V
+Lcom/android/ims/internal/uce/presence/PresCmdStatus;->setUserData(I)V
+Lcom/android/ims/internal/uce/presence/PresPublishTriggerType;->()V
+Lcom/android/ims/internal/uce/presence/PresPublishTriggerType;->setPublishTrigeerType(I)V
+Lcom/android/ims/internal/uce/presence/PresResInfo;->()V
+Lcom/android/ims/internal/uce/presence/PresResInfo;->setDisplayName(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInfo;->setInstanceInfo(Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;)V
+Lcom/android/ims/internal/uce/presence/PresResInfo;->setResUri(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->()V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setPresentityUri(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setReason(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setResId(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setResInstanceState(I)V
+Lcom/android/ims/internal/uce/presence/PresResInstanceInfo;->setTupleInfo([Lcom/android/ims/internal/uce/presence/PresTupleInfo;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->()V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setFullState(Z)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setListName(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setPresSubscriptionState(Lcom/android/ims/internal/uce/presence/PresSubscriptionState;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setRequestId(I)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setSubscriptionExpireTime(I)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setSubscriptionTerminatedReason(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setUri(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresRlmiInfo;->setVersion(I)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->()V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setCmdId(Lcom/android/ims/internal/uce/presence/PresCmdId;)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setReasonPhrase(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setRequestId(I)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setRetryAfter(I)V
+Lcom/android/ims/internal/uce/presence/PresSipResponse;->setSipResponseCode(I)V
+Lcom/android/ims/internal/uce/presence/PresSubscriptionState;->()V
+Lcom/android/ims/internal/uce/presence/PresSubscriptionState;->setPresSubscriptionState(I)V
+Lcom/android/ims/internal/uce/presence/PresTupleInfo;->()V
+Lcom/android/ims/internal/uce/presence/PresTupleInfo;->setContactUri(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresTupleInfo;->setFeatureTag(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/PresTupleInfo;->setTimestamp(Ljava/lang/String;)V
Lcom/android/internal/app/IAppOpsService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IAppOpsService;
Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I
Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->(Landroid/os/IBinder;)V
@@ -2366,6 +2477,7 @@ Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->(Landroid/os/IBinder;)V
Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I
Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;->(Landroid/os/IBinder;)V
+Lcom/android/internal/util/FastPrintWriter;->(Ljava/io/OutputStream;)V
Lcom/android/internal/util/XmlUtils;->readMapXml(Ljava/io/InputStream;)Ljava/util/HashMap;
Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager;
Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;->getEnabledInputMethodList()Ljava/util/List;
@@ -2431,6 +2543,7 @@ Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setSoWriteTimeout(I)V
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setUseSessionTickets(Z)V
Lcom/android/org/conscrypt/OpenSSLX509Certificate;->mContext:J
Lcom/android/org/conscrypt/TrustManagerImpl;->(Ljava/security/KeyStore;)V
+Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;)V
Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String;
Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList;
Ldalvik/system/BlockGuard;->getThreadPolicy()Ldalvik/system/BlockGuard$Policy;
@@ -2440,6 +2553,7 @@ Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard;
Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V
Ldalvik/system/CloseGuard;->warnIfOpen()V
Ldalvik/system/DexFile;->getClassNameList(Ljava/lang/Object;)[Ljava/lang/String;
+Ldalvik/system/DexFile;->isBackedByOatFile()Z
Ldalvik/system/DexFile;->loadClassBinaryName(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/util/List;)Ljava/lang/Class;
Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object;
Ldalvik/system/DexFile;->mFileName:Ljava/lang/String;
@@ -2560,6 +2674,7 @@ Ljava/lang/Thread;->priority:I
Ljava/lang/Throwable;->backtrace:Ljava/lang/Object;
Ljava/lang/Throwable;->cause:Ljava/lang/Throwable;
Ljava/lang/Throwable;->detailMessage:Ljava/lang/String;
+Ljava/lang/Throwable;->nativeFillInStackTrace()Ljava/lang/Object;
Ljava/lang/Throwable;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/lang/Throwable;->stackTrace:[Ljava/lang/StackTraceElement;
Ljava/lang/Throwable;->suppressedExceptions:Ljava/util/List;
@@ -2629,6 +2744,7 @@ Ljava/security/spec/ECParameterSpec;->getCurveName()Ljava/lang/String;
Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V
Ljava/security/Timestamp;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/text/ChoiceFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/DateFormat;->is24Hour:Ljava/lang/Boolean;
Ljava/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/text/DateFormatSymbols;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
@@ -2651,11 +2767,13 @@ Ljava/time/chrono/MinguoDate;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/chrono/ThaiBuddhistChronology;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/chrono/ThaiBuddhistDate;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/Duration;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/Duration;->toSeconds()Ljava/math/BigDecimal;
Ljava/time/Instant;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/LocalDate;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/LocalDateTime;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/LocalTime;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/MonthDay;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/OffsetDateTime;->(Ljava/time/LocalDateTime;Ljava/time/ZoneOffset;)V
Ljava/time/OffsetDateTime;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/OffsetTime;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/time/Period;->readObject(Ljava/io/ObjectInputStream;)V
@@ -2762,6 +2880,7 @@ Ljava/util/prefs/PreferenceChangeEvent;->writeObject(Ljava/io/ObjectOutputStream
Ljava/util/PriorityQueue;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/util/PriorityQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/Random;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Random;->seedUniquifier()J
Ljava/util/Random;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/regex/Matcher;->appendPos:I
Ljava/util/regex/Pattern;->readObject(Ljava/io/ObjectInputStream;)V
--
GitLab
From 3872238081a35cb4df6d574f2b0605e10eccf041 Mon Sep 17 00:00:00 2001
From: Mihai Popa
Date: Wed, 7 Mar 2018 19:56:21 +0000
Subject: [PATCH 055/488] [Magnifier-33] Add animation on line jump
This CL adds a simple motion animation when the magnifier jumps between
lines.
Bug: 74381647
Test: manual testing
Test: atest FrameworksCoreTests:android.widget.TextViewActivityTest
Test: atest CtsWidgetTestCases:android.widget.cts.TextViewTest
Change-Id: I27caba47b18e694f93739866d6fd69569cb89184
(cherry picked from commit 8175edc7555febe2fd9792a13abb346577b02c95)
Merged-In: I27caba47b18e694f93739866d6fd69569cb89184
---
core/java/android/widget/Editor.java | 105 ++++++++++++++++++++++++---
1 file changed, 96 insertions(+), 9 deletions(-)
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b1410f17c0e..92285c77e61 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -17,6 +17,7 @@
package android.widget;
import android.R;
+import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -100,6 +101,7 @@ import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.LinearInterpolator;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.EditorInfo;
@@ -201,11 +203,11 @@ public class Editor {
private final boolean mHapticTextHandleEnabled;
- private final Magnifier mMagnifier;
+ private final MagnifierMotionAnimator mMagnifierAnimator;
private final Runnable mUpdateMagnifierRunnable = new Runnable() {
@Override
public void run() {
- mMagnifier.update();
+ mMagnifierAnimator.update();
}
};
// Update the magnifier contents whenever anything in the view hierarchy is updated.
@@ -216,7 +218,7 @@ public class Editor {
new ViewTreeObserver.OnDrawListener() {
@Override
public void onDraw() {
- if (mMagnifier != null) {
+ if (mMagnifierAnimator != null) {
// Posting the method will ensure that updating the magnifier contents will
// happen right after the rendering of the current frame.
mTextView.post(mUpdateMagnifierRunnable);
@@ -372,7 +374,9 @@ public class Editor {
mHapticTextHandleEnabled = mTextView.getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enableHapticTextHandle);
- mMagnifier = FLAG_USE_MAGNIFIER ? new Magnifier(mTextView) : null;
+ if (FLAG_USE_MAGNIFIER) {
+ mMagnifierAnimator = new MagnifierMotionAnimator(new Magnifier(mTextView));
+ }
}
ParcelableParcel saveInstanceState() {
@@ -4310,6 +4314,88 @@ public class Editor {
}
}
+ private static class MagnifierMotionAnimator {
+ private static final long DURATION = 100 /* miliseconds */;
+
+ // The magnifier being animated.
+ private final Magnifier mMagnifier;
+ // A value animator used to animate the magnifier.
+ private final ValueAnimator mAnimator;
+
+ // Whether the magnifier is currently visible.
+ private boolean mMagnifierIsShowing;
+ // The coordinates of the magnifier when the currently running animation started.
+ private float mAnimationStartX;
+ private float mAnimationStartY;
+ // The coordinates of the magnifier in the latest animation frame.
+ private float mAnimationCurrentX;
+ private float mAnimationCurrentY;
+ // The latest coordinates the motion animator was asked to #show() the magnifier at.
+ private float mLastX;
+ private float mLastY;
+
+ private MagnifierMotionAnimator(final Magnifier magnifier) {
+ mMagnifier = magnifier;
+ // Prepare the animator used to run the motion animation.
+ mAnimator = ValueAnimator.ofFloat(0, 1);
+ mAnimator.setDuration(DURATION);
+ mAnimator.setInterpolator(new LinearInterpolator());
+ mAnimator.addUpdateListener((animation) -> {
+ // Interpolate to find the current position of the magnifier.
+ mAnimationCurrentX = mAnimationStartX
+ + (mLastX - mAnimationStartX) * animation.getAnimatedFraction();
+ mAnimationCurrentY = mAnimationStartY
+ + (mLastY - mAnimationStartY) * animation.getAnimatedFraction();
+ mMagnifier.show(mAnimationCurrentX, mAnimationCurrentY);
+ });
+ }
+
+ /**
+ * Shows the magnifier at a new position.
+ * If the y coordinate is different from the previous y coordinate
+ * (probably corresponding to a line jump in the text), a short
+ * animation is added to the jump.
+ */
+ private void show(final float x, final float y) {
+ final boolean startNewAnimation = mMagnifierIsShowing && y != mLastY;
+
+ if (startNewAnimation) {
+ if (mAnimator.isRunning()) {
+ mAnimator.cancel();
+ mAnimationStartX = mAnimationCurrentX;
+ mAnimationStartY = mAnimationCurrentY;
+ } else {
+ mAnimationStartX = mLastX;
+ mAnimationStartY = mLastY;
+ }
+ mAnimator.start();
+ } else {
+ if (!mAnimator.isRunning()) {
+ mMagnifier.show(x, y);
+ }
+ }
+ mLastX = x;
+ mLastY = y;
+ mMagnifierIsShowing = true;
+ }
+
+ /**
+ * Updates the content of the magnifier.
+ */
+ private void update() {
+ mMagnifier.update();
+ }
+
+ /**
+ * Dismisses the magnifier, or does nothing if it is already dismissed.
+ */
+ private void dismiss() {
+ mMagnifier.dismiss();
+ mAnimator.cancel();
+ mMagnifierIsShowing = false;
+ }
+ }
+
@VisibleForTesting
public abstract class HandleView extends View implements TextViewPositionListener {
protected Drawable mDrawable;
@@ -4711,7 +4797,8 @@ public class Editor {
} else {
rightBound += mTextView.getLayout().getLineRight(lineNumber);
}
- final float contentWidth = Math.round(mMagnifier.getWidth() / mMagnifier.getZoom());
+ final float contentWidth = Math.round(mMagnifierAnimator.mMagnifier.getWidth()
+ / mMagnifierAnimator.mMagnifier.getZoom());
if (touchXInView < leftBound - contentWidth / 2
|| touchXInView > rightBound + contentWidth / 2) {
// The touch is too far from the current line / selection, so hide the magnifier.
@@ -4728,7 +4815,7 @@ public class Editor {
}
protected final void updateMagnifier(@NonNull final MotionEvent event) {
- if (mMagnifier == null) {
+ if (mMagnifierAnimator == null) {
return;
}
@@ -4739,15 +4826,15 @@ public class Editor {
mRenderCursorRegardlessTiming = true;
mTextView.invalidateCursorPath();
suspendBlink();
- mMagnifier.show(showPosInView.x, showPosInView.y);
+ mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
} else {
dismissMagnifier();
}
}
protected final void dismissMagnifier() {
- if (mMagnifier != null) {
- mMagnifier.dismiss();
+ if (mMagnifierAnimator != null) {
+ mMagnifierAnimator.dismiss();
mRenderCursorRegardlessTiming = false;
resumeBlink();
}
--
GitLab
From fb4b6b8fd26a9dc9081d7a864e6d6ba609988975 Mon Sep 17 00:00:00 2001
From: Mihai Popa
Date: Thu, 1 Mar 2018 16:08:14 +0000
Subject: [PATCH 056/488] [Magnifier-28] Set corner radius
This CL updates both the magnifier and the floating toolbar to use the
dialogCornerRadius attribute for the corner radius of their windows. In
both we use its value defined in the default device theme, rather than
the value defined in the application's custom theme.
Bug: 70848492
Test: atest CtsWidgetTestCases:android.widget.cts.MagnifierTest
Change-Id: Ifcf4cff1f38fd18b7dbb4c1802390e3beb92cd3c
(cherry picked from commit 3dcbc2112d9a47779f2d6b1a54df729ae43aed7e)
Merged-In: Ifcf4cff1f38fd18b7dbb4c1802390e3beb92cd3c
---
core/java/android/widget/Magnifier.java | 57 ++++++++++++-------
.../internal/widget/FloatingToolbar.java | 3 +-
.../floating_popup_background_dark.xml | 4 +-
.../floating_popup_background_light.xml | 2 +-
4 files changed, 43 insertions(+), 23 deletions(-)
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 3db149a442d..e2601dcb91a 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -23,6 +23,7 @@ import android.annotation.TestApi;
import android.annotation.UiThread;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Outline;
@@ -34,6 +35,7 @@ import android.graphics.Rect;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
+import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.DisplayListCanvas;
import android.view.LayoutInflater;
@@ -49,6 +51,7 @@ import android.view.View;
import android.view.ViewParent;
import android.view.ViewRootImpl;
+import com.android.internal.R;
import com.android.internal.util.Preconditions;
/**
@@ -83,6 +86,8 @@ public final class Magnifier {
private final int mBitmapHeight;
// The elevation of the window containing the magnifier.
private final float mWindowElevation;
+ // The corner radius of the window containing the magnifier.
+ private final float mWindowCornerRadius;
// The center coordinates of the content that is to be magnified.
private final Point mCenterZoomCoords = new Point();
// Variables holding previous states, used for detecting redundant calls and invalidation.
@@ -104,17 +109,13 @@ public final class Magnifier {
public Magnifier(@NonNull View view) {
mView = Preconditions.checkNotNull(view);
final Context context = mView.getContext();
- final View content = LayoutInflater.from(context).inflate(
- com.android.internal.R.layout.magnifier, null);
- content.findViewById(com.android.internal.R.id.magnifier_inner).setClipToOutline(true);
- mWindowWidth = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.magnifier_width);
- mWindowHeight = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.magnifier_height);
- mWindowElevation = context.getResources().getDimension(
- com.android.internal.R.dimen.magnifier_elevation);
- mZoom = context.getResources().getFloat(
- com.android.internal.R.dimen.magnifier_zoom_scale);
+ final View content = LayoutInflater.from(context).inflate(R.layout.magnifier, null);
+ content.findViewById(R.id.magnifier_inner).setClipToOutline(true);
+ mWindowWidth = context.getResources().getDimensionPixelSize(R.dimen.magnifier_width);
+ mWindowHeight = context.getResources().getDimensionPixelSize(R.dimen.magnifier_height);
+ mWindowElevation = context.getResources().getDimension(R.dimen.magnifier_elevation);
+ mWindowCornerRadius = getDeviceDefaultDialogCornerRadius();
+ mZoom = context.getResources().getFloat(R.dimen.magnifier_zoom_scale);
mBitmapWidth = Math.round(mWindowWidth / mZoom);
mBitmapHeight = Math.round(mWindowHeight / mZoom);
// The view's surface coordinates will not be updated until the magnifier is first shown.
@@ -125,6 +126,21 @@ public final class Magnifier {
sPixelCopyHandlerThread.start();
}
+ /**
+ * Returns the device default theme dialog corner radius attribute.
+ * We retrieve this from the device default theme to avoid
+ * using the values set in the custom application themes.
+ */
+ private float getDeviceDefaultDialogCornerRadius() {
+ final Context deviceDefaultContext =
+ new ContextThemeWrapper(mView.getContext(), R.style.Theme_DeviceDefault);
+ final TypedArray ta = deviceDefaultContext.obtainStyledAttributes(
+ new int[]{android.R.attr.dialogCornerRadius});
+ final float dialogCornerRadius = ta.getDimension(0, 0);
+ ta.recycle();
+ return dialogCornerRadius;
+ }
+
/**
* Shows the magnifier on the screen.
*
@@ -178,7 +194,8 @@ public final class Magnifier {
if (mWindow == null) {
synchronized (mLock) {
mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(),
- getValidViewSurface(), mWindowWidth, mWindowHeight, mWindowElevation,
+ getValidViewSurface(),
+ mWindowWidth, mWindowHeight, mWindowElevation, mWindowCornerRadius,
Handler.getMain() /* draw the magnifier on the UI thread */, mLock,
mCallback);
}
@@ -271,7 +288,7 @@ public final class Magnifier {
// Compute the position of the magnifier window. Again, this has to be relative to the
// surface of the magnified view, as this surface is the parent of the magnifier surface.
final int verticalOffset = mView.getContext().getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.magnifier_offset);
+ R.dimen.magnifier_offset);
mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2;
mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalOffset;
}
@@ -393,7 +410,7 @@ public final class Magnifier {
InternalPopupWindow(final Context context, final Display display,
final Surface parentSurface,
- final int width, final int height, final float elevation,
+ final int width, final int height, final float elevation, final float cornerRadius,
final Handler handler, final Object lock, final Callback callback) {
mDisplay = display;
mLock = lock;
@@ -424,7 +441,8 @@ public final class Magnifier {
);
mBitmapRenderNode = createRenderNodeForBitmap(
"magnifier content",
- elevation
+ elevation,
+ cornerRadius
);
final DisplayListCanvas canvas = mRenderer.getRootNode().start(width, height);
@@ -442,7 +460,8 @@ public final class Magnifier {
mFrameDrawScheduled = false;
}
- private RenderNode createRenderNodeForBitmap(final String name, final float elevation) {
+ private RenderNode createRenderNodeForBitmap(final String name,
+ final float elevation, final float cornerRadius) {
final RenderNode bitmapRenderNode = RenderNode.create(name, null);
// Define the position of the bitmap in the parent render node. The surface regions
@@ -452,7 +471,7 @@ public final class Magnifier {
bitmapRenderNode.setElevation(elevation);
final Outline outline = new Outline();
- outline.setRoundRect(0, 0, mContentWidth, mContentHeight, 3);
+ outline.setRoundRect(0, 0, mContentWidth, mContentHeight, cornerRadius);
outline.setAlpha(1.0f);
bitmapRenderNode.setOutline(outline);
bitmapRenderNode.setClipToOutline(true);
@@ -658,8 +677,8 @@ public final class Magnifier {
final Resources resources = Resources.getSystem();
final float density = resources.getDisplayMetrics().density;
final PointF size = new PointF();
- size.x = resources.getDimension(com.android.internal.R.dimen.magnifier_width) / density;
- size.y = resources.getDimension(com.android.internal.R.dimen.magnifier_height) / density;
+ size.x = resources.getDimension(R.dimen.magnifier_width) / density;
+ size.y = resources.getDimension(R.dimen.magnifier_height) / density;
return size;
}
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index e3b1c01fd12..35aae15a809 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -1784,7 +1784,8 @@ public final class FloatingToolbar {
private static Context applyDefaultTheme(Context originalContext) {
TypedArray a = originalContext.obtainStyledAttributes(new int[]{R.attr.isLightTheme});
boolean isLightTheme = a.getBoolean(0, true);
- int themeId = isLightTheme ? R.style.Theme_Material_Light : R.style.Theme_Material;
+ int themeId
+ = isLightTheme ? R.style.Theme_DeviceDefault_Light : R.style.Theme_DeviceDefault;
a.recycle();
return new ContextThemeWrapper(originalContext, themeId);
}
diff --git a/core/res/res/drawable/floating_popup_background_dark.xml b/core/res/res/drawable/floating_popup_background_dark.xml
index ded1137576d..c4b44484d04 100644
--- a/core/res/res/drawable/floating_popup_background_dark.xml
+++ b/core/res/res/drawable/floating_popup_background_dark.xml
@@ -16,8 +16,8 @@
*/
-->
+ android:shape="rectangle">
-
+
diff --git a/core/res/res/drawable/floating_popup_background_light.xml b/core/res/res/drawable/floating_popup_background_light.xml
index 9c7a8860dde..767140d9d5c 100644
--- a/core/res/res/drawable/floating_popup_background_light.xml
+++ b/core/res/res/drawable/floating_popup_background_light.xml
@@ -18,6 +18,6 @@
-
+
--
GitLab
From fcd49f993ede363d0b17900565dfe37066362480 Mon Sep 17 00:00:00 2001
From: Rubin Xu
Date: Thu, 24 Aug 2017 18:21:52 +0100
Subject: [PATCH 057/488] Move escrow APIs into LockSettingsInternal
Remove the IPC interfaces so these APIs are only available to other
services running inside system server process only.
Bug: 62264551
Test: runtest frameworks-services -p com.android.server.locksettings
Change-Id: Ic7ac5df5fb977bc68a2c4daafaa3cdaf3ba66fcd
---
.../internal/widget/ILockSettings.aidl | 7 -
.../internal/widget/LockPatternUtils.java | 121 +++++++++---------
.../internal/widget/LockSettingsInternal.java | 56 ++++++++
.../locksettings/LockSettingsService.java | 97 ++++++++------
.../BaseLockSettingsServiceTests.java | 4 +
.../locksettings/SyntheticPasswordTests.java | 45 +++----
6 files changed, 206 insertions(+), 124 deletions(-)
create mode 100644 core/java/com/android/internal/widget/LockSettingsInternal.java
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 5a06f7fe199..25e1589db74 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -54,13 +54,6 @@ interface ILockSettings {
void userPresent(int userId);
int getStrongAuthForUser(int userId);
- long addEscrowToken(in byte[] token, int userId);
- boolean removeEscrowToken(long handle, int userId);
- boolean isEscrowTokenActive(long handle, int userId);
- boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
- in byte[] token, int requestedQuality, int userId);
- void unlockUserWithToken(long tokenHandle, in byte[] token, int userId);
-
// Keystore RecoveryController methods.
// {@code ServiceSpecificException} may be thrown to signal an error, which caller can
// convert to {@code RecoveryManagerException}.
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 7eb2f38f528..bf075bf800f 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -45,6 +45,7 @@ import android.util.SparseIntArray;
import android.util.SparseLongArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
import com.google.android.collect.Lists;
import libcore.util.HexEncoding;
@@ -1473,6 +1474,13 @@ public class LockPatternUtils {
}
}
+ private LockSettingsInternal getLockSettingsInternal() {
+ LockSettingsInternal service = LocalServices.getService(LockSettingsInternal.class);
+ if (service == null) {
+ throw new SecurityException("Only available to system server itself");
+ }
+ return service;
+ }
/**
* Create an escrow token for the current user, which can later be used to unlock FBE
* or change user password.
@@ -1481,44 +1489,41 @@ public class LockPatternUtils {
* confirm credential operation in order to activate the token for future use. If the user
* has no secure lockscreen, then the token is activated immediately.
*
+ *
This method is only available to code running in the system server process itself.
+ *
* @return a unique 64-bit token handle which is needed to refer to this token later.
*/
public long addEscrowToken(byte[] token, int userId) {
- try {
- return getLockSettings().addEscrowToken(token, userId);
- } catch (RemoteException re) {
- return 0L;
- }
+ return getLockSettingsInternal().addEscrowToken(token, userId);
}
/**
* Remove an escrow token.
+ *
+ *
This method is only available to code running in the system server process itself.
+ *
* @return true if the given handle refers to a valid token previously returned from
* {@link #addEscrowToken}, whether it's active or not. return false otherwise.
*/
public boolean removeEscrowToken(long handle, int userId) {
- try {
- return getLockSettings().removeEscrowToken(handle, userId);
- } catch (RemoteException re) {
- return false;
- }
+ return getLockSettingsInternal().removeEscrowToken(handle, userId);
}
/**
* Check if the given escrow token is active or not. Only active token can be used to call
* {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
+ *
+ *
This method is only available to code running in the system server process itself.
*/
public boolean isEscrowTokenActive(long handle, int userId) {
- try {
- return getLockSettings().isEscrowTokenActive(handle, userId);
- } catch (RemoteException re) {
- return false;
- }
+ return getLockSettingsInternal().isEscrowTokenActive(handle, userId);
}
/**
* Change a user's lock credential with a pre-configured escrow token.
*
+ *
This method is only available to code running in the system server process itself.
+ *
* @param credential The new credential to be set
* @param type Credential type: password / pattern / none.
* @param requestedQuality the requested password quality by DevicePolicyManager.
@@ -1530,55 +1535,55 @@ public class LockPatternUtils {
*/
public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality,
long tokenHandle, byte[] token, int userId) {
- try {
- if (type != CREDENTIAL_TYPE_NONE) {
- if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
- throw new IllegalArgumentException("password must not be null and at least "
- + "of length " + MIN_LOCK_PASSWORD_SIZE);
- }
- final int quality = computePasswordQuality(type, credential, requestedQuality);
- if (!getLockSettings().setLockCredentialWithToken(credential, type, tokenHandle,
- token, quality, userId)) {
- return false;
- }
- setLong(PASSWORD_TYPE_KEY, quality, userId);
+ LockSettingsInternal localService = getLockSettingsInternal();
+ if (type != CREDENTIAL_TYPE_NONE) {
+ if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
+ throw new IllegalArgumentException("password must not be null and at least "
+ + "of length " + MIN_LOCK_PASSWORD_SIZE);
+ }
+ final int quality = computePasswordQuality(type, credential, requestedQuality);
+ if (!localService.setLockCredentialWithToken(credential, type, tokenHandle,
+ token, quality, userId)) {
+ return false;
+ }
+ setLong(PASSWORD_TYPE_KEY, quality, userId);
- updateEncryptionPasswordIfNeeded(credential, quality, userId);
- updatePasswordHistory(credential, userId);
- } else {
- if (!TextUtils.isEmpty(credential)) {
- throw new IllegalArgumentException("password must be emtpy for NONE type");
- }
- if (!getLockSettings().setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
- tokenHandle, token, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
- userId)) {
- return false;
- }
- setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
- userId);
+ updateEncryptionPasswordIfNeeded(credential, quality, userId);
+ updatePasswordHistory(credential, userId);
+ } else {
+ if (!TextUtils.isEmpty(credential)) {
+ throw new IllegalArgumentException("password must be emtpy for NONE type");
+ }
+ if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
+ tokenHandle, token, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
+ userId)) {
+ return false;
+ }
+ setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
+ userId);
- if (userId == UserHandle.USER_SYSTEM) {
- // Set the encryption password to default.
- updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
- setCredentialRequiredToDecrypt(false);
- }
+ if (userId == UserHandle.USER_SYSTEM) {
+ // Set the encryption password to default.
+ updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
+ setCredentialRequiredToDecrypt(false);
}
- onAfterChangingPassword(userId);
- return true;
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to save lock password ", re);
- re.rethrowFromSystemServer();
}
- return false;
+ onAfterChangingPassword(userId);
+ return true;
}
- public void unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
- try {
- getLockSettings().unlockUserWithToken(tokenHandle, token, userId);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to unlock user with token", re);
- re.rethrowFromSystemServer();
- }
+ /**
+ * Unlock the specified user by an pre-activated escrow token. This should have the same effect
+ * on device encryption as the user entering his lockscreen credentials for the first time after
+ * boot, this includes unlocking the user's credential-encrypted storage as well as the keystore
+ *
+ *
This method is only available to code running in the system server process itself.
+ *
+ * @return {@code true} if the supplied token is valid and unlock succeeds,
+ * {@code false} otherwise.
+ */
+ public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
+ return getLockSettingsInternal().unlockUserWithToken(tokenHandle, token, userId);
}
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
new file mode 100644
index 00000000000..9de9ef7f2ae
--- /dev/null
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+
+/**
+ * LockSettingsService local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class LockSettingsInternal {
+
+ /**
+ * Create an escrow token for the current user, which can later be used to unlock FBE
+ * or change user password.
+ *
+ * After adding, if the user currently has lockscreen password, he will need to perform a
+ * confirm credential operation in order to activate the token for future use. If the user
+ * has no secure lockscreen, then the token is activated immediately.
+ *
+ * @return a unique 64-bit token handle which is needed to refer to this token later.
+ */
+ public abstract long addEscrowToken(byte[] token, int userId);
+
+ /**
+ * Remove an escrow token.
+ * @return true if the given handle refers to a valid token previously returned from
+ * {@link #addEscrowToken}, whether it's active or not. return false otherwise.
+ */
+ public abstract boolean removeEscrowToken(long handle, int userId);
+
+ /**
+ * Check if the given escrow token is active or not. Only active token can be used to call
+ * {@link #setLockCredentialWithToken} and {@link #unlockUserWithToken}
+ */
+ public abstract boolean isEscrowTokenActive(long handle, int userId);
+
+ public abstract boolean setLockCredentialWithToken(String credential, int type,
+ long tokenHandle, byte[] token, int requestedQuality, int userId);
+
+ public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId);
+}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 468ec591caa..74ebf3e4461 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -102,6 +102,7 @@ import com.android.internal.util.Preconditions;
import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -436,6 +437,8 @@ public class LockSettingsService extends ILockSettings.Stub {
mStrongAuthTracker.register(mStrongAuth);
mSpManager = injector.getSyntheticPasswordManager(mStorage);
+
+ LocalServices.addService(LockSettingsInternal.class, new LocalService());
}
/**
@@ -1041,14 +1044,10 @@ public class LockSettingsService extends ILockSettings.Stub {
private boolean isUserSecure(int userId) {
synchronized (mSpManager) {
- try {
- if (isSyntheticPasswordBasedCredentialLocked(userId)) {
- long handle = getSyntheticPasswordHandleLocked(userId);
- return mSpManager.getCredentialType(handle, userId) !=
- LockPatternUtils.CREDENTIAL_TYPE_NONE;
- }
- } catch (RemoteException e) {
- // fall through
+ if (isSyntheticPasswordBasedCredentialLocked(userId)) {
+ long handle = getSyntheticPasswordHandleLocked(userId);
+ return mSpManager.getCredentialType(handle, userId) !=
+ LockPatternUtils.CREDENTIAL_TYPE_NONE;
}
}
return mStorage.hasCredential(userId);
@@ -2305,7 +2304,7 @@ public class LockSettingsService extends ILockSettings.Stub {
SyntheticPasswordManager.DEFAULT_HANDLE, userId);
}
- private boolean isSyntheticPasswordBasedCredentialLocked(int userId) throws RemoteException {
+ private boolean isSyntheticPasswordBasedCredentialLocked(int userId) {
if (userId == USER_FRP) {
final int type = mStorage.readPersistentDataBlock().type;
return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
@@ -2318,7 +2317,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@VisibleForTesting
- protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException {
+ protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) {
long handle = getSyntheticPasswordHandleLocked(userId);
// This is a global setting
long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
@@ -2326,7 +2325,7 @@ public class LockSettingsService extends ILockSettings.Stub {
return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
}
- private void enableSyntheticPasswordLocked() throws RemoteException {
+ private void enableSyntheticPasswordLocked() {
setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
}
@@ -2525,9 +2524,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
}
- @Override
- public long addEscrowToken(byte[] token, int userId) throws RemoteException {
- ensureCallerSystemUid();
+ private long addEscrowToken(byte[] token, int userId) throws RemoteException {
if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
synchronized (mSpManager) {
enableSyntheticPasswordLocked();
@@ -2559,7 +2556,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException {
+ private void activateEscrowTokens(AuthenticationToken auth, int userId) {
if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
synchronized (mSpManager) {
disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
@@ -2570,17 +2567,13 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- @Override
- public boolean isEscrowTokenActive(long handle, int userId) throws RemoteException {
- ensureCallerSystemUid();
+ private boolean isEscrowTokenActive(long handle, int userId) {
synchronized (mSpManager) {
return mSpManager.existsHandle(handle, userId);
}
}
- @Override
- public boolean removeEscrowToken(long handle, int userId) throws RemoteException {
- ensureCallerSystemUid();
+ private boolean removeEscrowToken(long handle, int userId) {
synchronized (mSpManager) {
if (handle == getSyntheticPasswordHandleLocked(userId)) {
Slog.w(TAG, "Cannot remove password handle");
@@ -2598,10 +2591,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- @Override
- public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
+ private boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
byte[] token, int requestedQuality, int userId) throws RemoteException {
- ensureCallerSystemUid();
boolean result;
synchronized (mSpManager) {
if (!mSpManager.hasEscrowData(userId)) {
@@ -2650,10 +2641,8 @@ public class LockSettingsService extends ILockSettings.Stub {
return true;
}
- @Override
- public void unlockUserWithToken(long tokenHandle, byte[] token, int userId)
+ private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId)
throws RemoteException {
- ensureCallerSystemUid();
AuthenticationResult authResult;
synchronized (mSpManager) {
if (!mSpManager.hasEscrowData(userId)) {
@@ -2663,11 +2652,12 @@ public class LockSettingsService extends ILockSettings.Stub {
tokenHandle, token, userId);
if (authResult.authToken == null) {
Slog.w(TAG, "Invalid escrow token supplied");
- return;
+ return false;
}
}
unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey());
onAuthTokenKnownForUser(userId, authResult.authToken);
+ return true;
}
@Override
@@ -2732,20 +2722,11 @@ public class LockSettingsService extends ILockSettings.Stub {
if (isSyntheticPasswordBasedCredentialLocked(userId)) {
mSpManager.destroyEscrowData(userId);
}
- } catch (RemoteException e) {
- Slog.e(TAG, "disableEscrowTokenOnNonManagedDevices", e);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- private void ensureCallerSystemUid() throws SecurityException {
- final int callingUid = mInjector.binderGetCallingUid();
- if (callingUid != Process.SYSTEM_UID) {
- throw new SecurityException("Only system can call this API.");
- }
- }
-
private class DeviceProvisionedObserver extends ContentObserver {
private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor(
Settings.Global.DEVICE_PROVISIONED);
@@ -2834,4 +2815,46 @@ public class LockSettingsService extends ILockSettings.Stub {
Settings.Global.DEVICE_PROVISIONED, 0) != 0;
}
}
+
+ private final class LocalService extends LockSettingsInternal {
+
+ @Override
+ public long addEscrowToken(byte[] token, int userId) {
+ try {
+ return LockSettingsService.this.addEscrowToken(token, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public boolean removeEscrowToken(long handle, int userId) {
+ return LockSettingsService.this.removeEscrowToken(handle, userId);
+ }
+
+ @Override
+ public boolean isEscrowTokenActive(long handle, int userId) {
+ return LockSettingsService.this.isEscrowTokenActive(handle, userId);
+ }
+
+ @Override
+ public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
+ byte[] token, int requestedQuality, int userId) {
+ try {
+ return LockSettingsService.this.setLockCredentialWithToken(credential, type,
+ tokenHandle, token, requestedQuality, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) {
+ try {
+ return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index e8648701bd0..96f81606a98 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -43,6 +43,7 @@ import android.test.AndroidTestCase;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockSettingsInternal;
import com.android.server.LocalServices;
import org.mockito.invocation.InvocationOnMock;
@@ -67,6 +68,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase {
private ArrayList mPrimaryUserProfiles = new ArrayList<>();
LockSettingsService mService;
+ LockSettingsInternal mLocalService;
MockLockSettingsContext mContext;
LockSettingsStorageTestable mStorage;
@@ -95,6 +97,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase {
mDevicePolicyManager = mock(DevicePolicyManager.class);
mDevicePolicyManagerInternal = mock(DevicePolicyManagerInternal.class);
+ LocalServices.removeServiceForTest(LockSettingsInternal.class);
LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
LocalServices.addService(DevicePolicyManagerInternal.class, mDevicePolicyManagerInternal);
@@ -146,6 +149,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase {
// Adding a fake Device Owner app which will enable escrow token support in LSS.
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(
new ComponentName("com.dummy.package", ".FakeDeviceOwner"));
+ mLocalService = LocalServices.getService(LockSettingsInternal.class);
}
private UserInfo installChildProfile(int profileId) {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 294c3e99ad7..e9f9800f219 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -300,14 +300,14 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
- assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
PRIMARY_USER_ID).getResponseCode();
- assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
// Verify DPM gets notified about new device lock
@@ -329,16 +329,16 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
- assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
0, PRIMARY_USER_ID).getResponseCode();
- assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, handle,
- TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
- mService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ mLocalService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
+ handle, TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
@@ -355,18 +355,19 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
- assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
0, PRIMARY_USER_ID).getResponseCode();
- assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.setLockCredential(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, PASSWORD,
PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
- mService.setLockCredentialWithToken(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- handle, TOKEN.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(NEWPASSWORD,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, TOKEN.getBytes(),
+ PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
@@ -378,8 +379,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
throws RemoteException {
final String TOKEN = "some-high-entropy-secure-token";
enableSyntheticPassword();
- long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
- assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
}
@@ -388,8 +389,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
throws RemoteException {
final String TOKEN = "some-high-entropy-secure-token";
initializeCredentialUnderSP(null, PRIMARY_USER_ID);
- long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
- assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
}
@@ -404,15 +405,15 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
enableSyntheticPassword();
- long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
// Token not activated immediately since user password exists
- assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
// Activate token (password gets migrated to SP at the same time)
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
// Verify token is activated
- assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
}
public void testPasswordData_serializeDeserialize() {
--
GitLab
From 60719a4e7448f36dad8054740fb8becb2f1fb43f Mon Sep 17 00:00:00 2001
From: Bernardo Rufino
Date: Fri, 9 Mar 2018 12:43:48 +0000
Subject: [PATCH 058/488] Add measurements for TransportClient connections
Retrievable via 'adb shell dumpsys backup transportstats'.
Sample output:
Average connection time: 36.00 ms
Max connection time: 181 ms
Min connection time: 7 ms
Number of connections: 16
Per transport:
com.google.android.gms/.backup.BackupTransportService
Average connection time: 27.71 ms
Max connection time: 139 ms
Min connection time: 13 ms
Number of connections: 14
com.google.android.gms/.backup.component.D2dTransportService
Average connection time: 181.00 ms
Max connection time: 181 ms
Min connection time: 181 ms
Number of connections: 1
android/com.android.internal.backup.LocalTransportService
Average connection time: 7.00 ms
Max connection time: 7 ms
Min connection time: 7 ms
Number of connections: 1
Bug: 72485465
Test: Will follow in another CL if reviewers OK w/ approach.
Change-Id: I133ed423d0b8471d69e3c3631aadee7d42d0ec0e
(cherry picked from commit e5a976404c66c054fbec9b124f816a90f9d6b4dc)
---
.../server/backup/BackupManagerService.java | 7 +-
.../server/backup/TransportManager.java | 16 ++-
.../backup/transport/TransportClient.java | 14 +-
.../transport/TransportClientManager.java | 5 +-
.../backup/transport/TransportStats.java | 122 ++++++++++++++++++
.../transport/TransportClientManagerTest.java | 2 +-
.../backup/transport/TransportClientTest.java | 3 +
7 files changed, 162 insertions(+), 7 deletions(-)
create mode 100644 services/backup/java/com/android/server/backup/transport/TransportStats.java
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 369df540581..646909177e7 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3525,7 +3525,10 @@ public class BackupManagerService implements BackupManagerServiceInterface {
dumpAgents(pw);
return;
} else if ("transportclients".equals(arg.toLowerCase())) {
- mTransportManager.dump(pw);
+ mTransportManager.dumpTransportClients(pw);
+ return;
+ } else if ("transportstats".equals(arg.toLowerCase())) {
+ mTransportManager.dumpTransportStats(pw);
return;
}
}
@@ -3590,7 +3593,7 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
}
- mTransportManager.dump(pw);
+ mTransportManager.dumpTransportClients(pw);
pw.println("Pending init: " + mPendingInits.size());
for (String s : mPendingInits) {
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index c87d2987d0b..6a1bf178ad6 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -44,6 +44,7 @@ import com.android.server.backup.transport.TransportClientManager;
import com.android.server.backup.transport.TransportConnectionListener;
import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.transport.TransportNotRegisteredException;
+import com.android.server.backup.transport.TransportStats;
import java.io.PrintWriter;
import java.util.List;
@@ -64,6 +65,7 @@ public class TransportManager {
private final PackageManager mPackageManager;
private final Set mTransportWhitelist;
private final TransportClientManager mTransportClientManager;
+ private final TransportStats mTransportStats;
private OnTransportRegisteredListener mOnTransportRegisteredListener = (c, n) -> {};
/**
@@ -85,7 +87,12 @@ public class TransportManager {
private volatile String mCurrentTransportName;
TransportManager(Context context, Set whitelist, String selectedTransport) {
- this(context, whitelist, selectedTransport, new TransportClientManager(context));
+ mContext = context;
+ mPackageManager = context.getPackageManager();
+ mTransportWhitelist = Preconditions.checkNotNull(whitelist);
+ mCurrentTransportName = selectedTransport;
+ mTransportStats = new TransportStats();
+ mTransportClientManager = new TransportClientManager(context, mTransportStats);
}
@VisibleForTesting
@@ -98,6 +105,7 @@ public class TransportManager {
mPackageManager = context.getPackageManager();
mTransportWhitelist = Preconditions.checkNotNull(whitelist);
mCurrentTransportName = selectedTransport;
+ mTransportStats = new TransportStats();
mTransportClientManager = transportClientManager;
}
@@ -640,10 +648,14 @@ public class TransportManager {
!Thread.holdsLock(mTransportLock), "Can't call transport with transport lock held");
}
- public void dump(PrintWriter pw) {
+ public void dumpTransportClients(PrintWriter pw) {
mTransportClientManager.dump(pw);
}
+ public void dumpTransportStats(PrintWriter pw) {
+ mTransportStats.dump(pw);
+ }
+
private static Predicate fromPackageFilter(String packageName) {
return transportComponent -> packageName.equals(transportComponent.getPackageName());
}
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClient.java b/services/backup/java/com/android/server/backup/transport/TransportClient.java
index 1a2ca923229..fa881a97d42 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClient.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClient.java
@@ -29,6 +29,7 @@ import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.text.format.DateFormat;
import android.util.ArrayMap;
@@ -51,6 +52,7 @@ import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -78,6 +80,7 @@ public class TransportClient {
private static final int LOG_BUFFER_SIZE = 5;
private final Context mContext;
+ private final TransportStats mTransportStats;
private final Intent mBindIntent;
private final ServiceConnection mConnection;
private final String mIdentifier;
@@ -104,12 +107,14 @@ public class TransportClient {
TransportClient(
Context context,
+ TransportStats transportStats,
Intent bindIntent,
ComponentName transportComponent,
String identifier,
String caller) {
this(
context,
+ transportStats,
bindIntent,
transportComponent,
identifier,
@@ -120,12 +125,14 @@ public class TransportClient {
@VisibleForTesting
TransportClient(
Context context,
+ TransportStats transportStats,
Intent bindIntent,
ComponentName transportComponent,
String identifier,
String caller,
Handler listenerHandler) {
mContext = context;
+ mTransportStats = transportStats;
mTransportComponent = transportComponent;
mBindIntent = bindIntent;
mIdentifier = identifier;
@@ -321,11 +328,16 @@ public class TransportClient {
(requestedTransport, transportClient) ->
transportFuture.complete(requestedTransport);
+ long requestTime = SystemClock.elapsedRealtime();
log(Priority.DEBUG, caller, "Sync connect: calling async");
connectAsync(requestListener, caller);
try {
- return transportFuture.get();
+ transport = transportFuture.get();
+ long time = SystemClock.elapsedRealtime() - requestTime;
+ mTransportStats.registerConnectionTime(mTransportComponent, time);
+ log(Priority.DEBUG, caller, String.format(Locale.US, "Connect took %d ms", time));
+ return transport;
} catch (InterruptedException | ExecutionException e) {
String error = e.getClass().getSimpleName();
log(Priority.ERROR, caller, error + " while waiting for transport: " + e.getMessage());
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
index 96e7d2f5361..f4e39287b27 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
@@ -37,12 +37,14 @@ public class TransportClientManager {
private static final String TAG = "TransportClientManager";
private final Context mContext;
+ private final TransportStats mTransportStats;
private final Object mTransportClientsLock = new Object();
private int mTransportClientsCreated = 0;
private Map mTransportClientsCallerMap = new WeakHashMap<>();
- public TransportClientManager(Context context) {
+ public TransportClientManager(Context context, TransportStats transportStats) {
mContext = context;
+ mTransportStats = transportStats;
}
/**
@@ -88,6 +90,7 @@ public class TransportClientManager {
TransportClient transportClient =
new TransportClient(
mContext,
+ mTransportStats,
bindIntent,
transportComponent,
Integer.toString(mTransportClientsCreated),
diff --git a/services/backup/java/com/android/server/backup/transport/TransportStats.java b/services/backup/java/com/android/server/backup/transport/TransportStats.java
new file mode 100644
index 00000000000..4bef81aad10
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/transport/TransportStats.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.transport;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+
+/** Responsible for aggregating {@link TransportClient} relevant times. */
+public class TransportStats {
+ private final Object mStatsLock = new Object();
+ private final Map mTransportStats = new HashMap<>();
+
+ void registerConnectionTime(ComponentName transportComponent, long timeMs) {
+ synchronized (mStatsLock) {
+ mTransportStats
+ .computeIfAbsent(transportComponent, name -> new Stats())
+ .register(timeMs);
+ }
+ }
+
+ /** Returns {@link Stats} for transport whose host service is {@code transportComponent}. */
+ @Nullable
+ public Stats getStatsForTransport(ComponentName transportComponent) {
+ synchronized (mStatsLock) {
+ Stats stats = mTransportStats.get(transportComponent);
+ if (stats == null) {
+ return null;
+ }
+ return new Stats(stats);
+ }
+ }
+
+ public void dump(PrintWriter pw) {
+ synchronized (mStatsLock) {
+ Optional aggregatedStats =
+ mTransportStats.values().stream().reduce(Stats::merge);
+ if (aggregatedStats.isPresent()) {
+ dumpStats(pw, "", aggregatedStats.get());
+ }
+ if (!mTransportStats.isEmpty()) {
+ pw.println("Per transport:");
+ for (ComponentName transportComponent : mTransportStats.keySet()) {
+ Stats stats = mTransportStats.get(transportComponent);
+ pw.println(" " + transportComponent.flattenToShortString());
+ dumpStats(pw, " ", stats);
+ }
+ }
+ }
+ }
+
+ private static void dumpStats(PrintWriter pw, String prefix, Stats stats) {
+ pw.println(
+ String.format(
+ Locale.US, "%sAverage connection time: %.2f ms", prefix, stats.mAverage));
+ pw.println(String.format(Locale.US, "%sMax connection time: %d ms", prefix, stats.mMax));
+ pw.println(String.format(Locale.US, "%sMin connection time: %d ms", prefix, stats.mMin));
+ pw.println(String.format(Locale.US, "%sNumber of connections: %d ", prefix, stats.mN));
+ }
+
+ public static final class Stats {
+ public static Stats merge(Stats a, Stats b) {
+ return new Stats(
+ a.mN + b.mN,
+ (a.mAverage * a.mN + b.mAverage * b.mN) / (a.mN + b.mN),
+ Math.max(a.mMax, b.mMax),
+ Math.min(a.mMin, b.mMin));
+ }
+
+ public int mN;
+ public double mAverage;
+ public long mMax;
+ public long mMin;
+
+ public Stats() {
+ mN = 0;
+ mAverage = 0;
+ mMax = 0;
+ mMin = Long.MAX_VALUE;
+ }
+
+ private Stats(Stats original) {
+ mN = original.mN;
+ mAverage = original.mAverage;
+ mMax = original.mMax;
+ mMin = original.mMin;
+ }
+
+ private Stats(int n, double average, long max, long min) {
+ mN = n;
+ mAverage = average;
+ mMax = max;
+ mMin = min;
+ }
+
+ private void register(long sample) {
+ mAverage = (mAverage * mN + sample) / (mN + 1);
+ mN++;
+ mMax = Math.max(mMax, sample);
+ mMin = Math.min(mMin, sample);
+ }
+ }
+}
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
index 3d2d8afd4a3..bbec7af34d7 100644
--- a/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
@@ -60,7 +60,7 @@ public class TransportClientManagerTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
- mTransportClientManager = new TransportClientManager(mContext);
+ mTransportClientManager = new TransportClientManager(mContext, new TransportStats());
mTransportComponent = new ComponentName(PACKAGE_NAME, CLASS_NAME);
mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
index 5b65473e078..49ef581f03b 100644
--- a/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
+++ b/services/robotests/src/com/android/server/backup/transport/TransportClientTest.java
@@ -88,6 +88,7 @@ public class TransportClientTest {
@Mock private TransportConnectionListener mTransportConnectionListener;
@Mock private TransportConnectionListener mTransportConnectionListener2;
@Mock private IBackupTransport.Stub mTransportBinder;
+ private TransportStats mTransportStats;
private TransportClient mTransportClient;
private ComponentName mTransportComponent;
private String mTransportString;
@@ -105,10 +106,12 @@ public class TransportClientTest {
mTransportComponent =
new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".transport.Transport");
mTransportString = mTransportComponent.flattenToShortString();
+ mTransportStats = new TransportStats();
mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
mTransportClient =
new TransportClient(
mContext,
+ mTransportStats,
mBindIntent,
mTransportComponent,
"1",
--
GitLab
From 22db49485e7e708d75d6ba79fbb9c60f1dca1ff1 Mon Sep 17 00:00:00 2001
From: Michael Wright
Date: Fri, 9 Mar 2018 23:10:20 +0000
Subject: [PATCH 059/488] Expose the new brightness permissions as test APIs.
Bug: 74332874
Test: atest BrightnessTest
Change-Id: Icd341c8813a8f2e806db3f75d6b1f141b56b2911
---
api/test-current.txt | 9 +++++++++
core/res/AndroidManifest.xml | 6 ++++--
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/api/test-current.txt b/api/test-current.txt
index 9d67f4c3bb6..54ddd5de796 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1,3 +1,12 @@
+package android {
+
+ public static final class Manifest.permission {
+ field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
+ field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
+ }
+
+}
+
package android.animation {
public class ValueAnimator extends android.animation.Animator {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7aec8125c7d..687e379cf3f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3088,7 +3088,8 @@
+ @SystemApi
+ @TestApi -->
@@ -3101,7 +3102,8 @@
+ @SystemApi
+ @TestApi -->
--
GitLab
From a2689a9a11067dfedb9cfb27a3098efeb18c3eb3 Mon Sep 17 00:00:00 2001
From: Artem Iglikov
Date: Mon, 12 Mar 2018 11:21:56 +0000
Subject: [PATCH 060/488] Whitelist UsbManager and UsbPortStatus apis
Bug: 74424953
Test: N/A
Change-Id: I8e96e3c81067a65430c58ab3f7fa2013a52d2be5
---
config/hiddenapi-light-greylist.txt | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 1a1d431b1d2..7a9a953c452 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -681,7 +681,13 @@ Landroid/hardware/SystemSensorManager$BaseEventQueue;->dispatchFlushCompleteEven
Landroid/hardware/SystemSensorManager$BaseEventQueue;->dispatchSensorEvent(I[FIJ)V
Landroid/hardware/usb/IUsbManager$Stub$Proxy;->(Landroid/os/IBinder;)V
Landroid/hardware/usb/UsbDeviceConnection;->mNativeContext:J
+Landroid/hardware/usb/UsbManager;->getPorts()[Landroid/hardware/usb/UsbPort;
+Landroid/hardware/usb/UsbManager;->getPortStatus(Landroid/hardware/usb/UsbPort;)Landroid/hardware/usb/UsbPortStatus;
Landroid/hardware/usb/UsbManager;->setCurrentFunction(Ljava/lang/String;Z)V
+Landroid/hardware/usb/UsbManager;->setPortRoles(Landroid/hardware/usb/UsbPort;II)V
+Landroid/hardware/usb/UsbPortStatus;->getCurrentDataRole()I
+Landroid/hardware/usb/UsbPortStatus;->isConnected()Z
+Landroid/hardware/usb/UsbPortStatus;->isRoleCombinationSupported(II)Z
Landroid/hardware/usb/UsbRequest;->mNativeContext:J
Landroid/icu/impl/number/DecimalFormatProperties;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/icu/impl/number/DecimalFormatProperties;->writeObject(Ljava/io/ObjectOutputStream;)V
--
GitLab
From 1fac86e6cdb3ca9d0b3b3ba8515d81a3b4e00b9b Mon Sep 17 00:00:00 2001
From: Julia Reynolds
Date: Wed, 7 Mar 2018 08:30:37 -0500
Subject: [PATCH 061/488] Log interruptive notifications
First pass only logs audibly interruptive notfications; visually
interruptive notifications will be added in a future CL
Test: runtest systemui-notification, cts
Bug: 74318867
Change-Id: I604495bd4af9741ec52c38e4faa17cc87e2a522b
---
api/system-current.txt | 2 +
core/java/android/app/usage/UsageEvents.java | 34 ++++++++++++
.../app/usage/UsageStatsManagerInternal.java | 10 ++++
.../NotificationManagerService.java | 24 ++++++--
.../notification/NotificationRecord.java | 10 ++++
.../notification/BuzzBeepBlinkTest.java | 55 ++++++++++++++++++-
.../server/usage/UsageStatsService.java | 19 +++++++
.../server/usage/UserUsageStatsService.java | 2 +
8 files changed, 148 insertions(+), 8 deletions(-)
diff --git a/api/system-current.txt b/api/system-current.txt
index d35a06be45d..75bae5c68f9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -716,7 +716,9 @@ package android.app.usage {
}
public static final class UsageEvents.Event {
+ method public java.lang.String getNotificationChannelId();
method public int getStandbyBucket();
+ field public static final int NOTIFICATION_INTERRUPTION = 12; // 0xc
field public static final int NOTIFICATION_SEEN = 10; // 0xa
field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb
}
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 521ab4edc4c..f7fb84ba9d0 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -116,6 +116,14 @@ public final class UsageEvents implements Parcelable {
@SystemApi
public static final int STANDBY_BUCKET_CHANGED = 11;
+ /**
+ * An event type denoting that an app posted an interruptive notification. Visual and
+ * audible interruptions are included.
+ * @hide
+ */
+ @SystemApi
+ public static final int NOTIFICATION_INTERRUPTION = 12;
+
/** @hide */
public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
@@ -188,6 +196,14 @@ public final class UsageEvents implements Parcelable {
*/
public int mBucketAndReason;
+ /**
+ * The id of the {@link android.app.NotificationChannel} to which an interruptive
+ * notification was posted.
+ * Only present for {@link #NOTIFICATION_INTERRUPTION} event types.
+ * {@hide}
+ */
+ public String mNotificationChannelId;
+
/** @hide */
@EventFlags
public int mFlags;
@@ -208,6 +224,7 @@ public final class UsageEvents implements Parcelable {
mContentAnnotations = orig.mContentAnnotations;
mFlags = orig.mFlags;
mBucketAndReason = orig.mBucketAndReason;
+ mNotificationChannelId = orig.mNotificationChannelId;
}
/**
@@ -285,6 +302,16 @@ public final class UsageEvents implements Parcelable {
return mBucketAndReason & 0x0000FFFF;
}
+ /**
+ * Returns the ID of the {@link android.app.NotificationChannel} for this event if the
+ * event is of type {@link #NOTIFICATION_INTERRUPTION}, otherwise it returns null;
+ * @hide
+ */
+ @SystemApi
+ public String getNotificationChannelId() {
+ return mNotificationChannelId;
+ }
+
/** @hide */
public Event getObfuscatedIfInstantApp() {
if ((mFlags & FLAG_IS_PACKAGE_INSTANT_APP) == 0) {
@@ -444,6 +471,9 @@ public final class UsageEvents implements Parcelable {
case Event.STANDBY_BUCKET_CHANGED:
p.writeInt(event.mBucketAndReason);
break;
+ case Event.NOTIFICATION_INTERRUPTION:
+ p.writeString(event.mNotificationChannelId);
+ break;
}
}
@@ -473,6 +503,7 @@ public final class UsageEvents implements Parcelable {
eventOut.mAction = null;
eventOut.mContentType = null;
eventOut.mContentAnnotations = null;
+ eventOut.mNotificationChannelId = null;
switch (eventOut.mEventType) {
case Event.CONFIGURATION_CHANGE:
@@ -490,6 +521,9 @@ public final class UsageEvents implements Parcelable {
case Event.STANDBY_BUCKET_CHANGED:
eventOut.mBucketAndReason = p.readInt();
break;
+ case Event.NOTIFICATION_INTERRUPTION:
+ eventOut.mNotificationChannelId = p.readString();
+ break;
}
}
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index b62b1ee0492..09ced2648de 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -58,6 +58,16 @@ public abstract class UsageStatsManagerInternal {
*/
public abstract void reportConfigurationChange(Configuration config, @UserIdInt int userId);
+ /**
+ * Reports that an application has posted an interruptive notification.
+ *
+ * @param packageName The package name of the app that posted the notification
+ * @param channelId The ID of the NotificationChannel to which the notification was posted
+ * @param userId The user in which the notification was posted
+ */
+ public abstract void reportInterruptiveNotification(String packageName, String channelId,
+ @UserIdInt int userId);
+
/**
* Reports that an action equivalent to a ShortcutInfo is taken by the user.
*
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b68b98da9a2..b9fb2e012e0 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1782,11 +1782,10 @@ public class NotificationManagerService extends SystemService {
* Report to usage stats that the notification was seen.
* @param r notification record
*/
+ @GuardedBy("mNotificationLock")
protected void reportSeen(NotificationRecord r) {
- final int userId = r.sbn.getUserId();
mAppUsageStats.reportEvent(r.sbn.getPackageName(),
- userId == UserHandle.USER_ALL ? USER_SYSTEM
- : userId,
+ getRealUserId(r.sbn.getUserId()),
UsageEvents.Event.NOTIFICATION_SEEN);
}
@@ -1858,17 +1857,30 @@ public class NotificationManagerService extends SystemService {
return newSuppressedVisualEffects;
}
+ // TODO: log visual differences, not just audible ones
+ @GuardedBy("mNotificationLock")
+ protected void maybeRecordInterruptionLocked(NotificationRecord r) {
+ if (r.isInterruptive()) {
+ mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
+ r.getChannel().getId(),
+ getRealUserId(r.sbn.getUserId()));
+ }
+ }
+
/**
* Report to usage stats that the notification was clicked.
* @param r notification record
*/
protected void reportUserInteraction(NotificationRecord r) {
- final int userId = r.sbn.getUserId();
mAppUsageStats.reportEvent(r.sbn.getPackageName(),
- userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId,
+ getRealUserId(r.sbn.getUserId()),
UsageEvents.Event.USER_INTERACTION);
}
+ private int getRealUserId(int userId) {
+ return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
+ }
+
@VisibleForTesting
NotificationManagerInternal getInternalService() {
return mInternalService;
@@ -4345,6 +4357,7 @@ public class NotificationManagerService extends SystemService {
}
buzzBeepBlinkLocked(r);
+ maybeRecordInterruptionLocked(r);
} finally {
int N = mEnqueuedNotifications.size();
for (int i = 0; i < N; i++) {
@@ -4554,6 +4567,7 @@ public class NotificationManagerService extends SystemService {
updateLightsLocked();
}
if (buzz || beep || blink) {
+ record.setInterruptive(true);
MetricsLogger.action(record.getLogMaker()
.setCategory(MetricsEvent.NOTIFICATION_ALERT)
.setType(MetricsEvent.TYPE_OPEN)
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 4404c4848c6..f1908bff2d9 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -145,6 +145,7 @@ public final class NotificationRecord {
private final List mAdjustments;
private final NotificationStats mStats;
private int mUserSentiment;
+ private boolean mIsInterruptive;
@VisibleForTesting
public NotificationRecord(Context context, StatusBarNotification sbn,
@@ -519,6 +520,7 @@ public final class NotificationRecord {
pw.println(prefix + "mLight= " + mLight);
pw.println(prefix + "mShowBadge=" + mShowBadge);
pw.println(prefix + "mColorized=" + notification.isColorized());
+ pw.println(prefix + "mIsInterruptive=" + mIsInterruptive);
pw.println(prefix + "effectiveNotificationChannel=" + getChannel());
if (getPeopleOverride() != null) {
pw.println(prefix + "overridePeople= " + TextUtils.join(",", getPeopleOverride()));
@@ -888,6 +890,14 @@ public final class NotificationRecord {
return mPeopleOverride;
}
+ public void setInterruptive(boolean interruptive) {
+ mIsInterruptive = interruptive;
+ }
+
+ public boolean isInterruptive() {
+ return mIsInterruptive;
+ }
+
protected void setPeopleOverride(ArrayList people) {
mPeopleOverride = people;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index a92f7e7af5d..cb64c9c5edd 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -21,6 +21,7 @@ import static android.app.Notification.GROUP_ALERT_SUMMARY;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_MIN;
+import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
@@ -389,6 +390,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(r);
verifyLights();
+ assertTrue(r.isInterruptive());
}
@Test
@@ -400,6 +402,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
verifyBeepLooped();
verifyNeverVibrate();
verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
+ assertTrue(r.isInterruptive());
}
@Test
@@ -409,6 +412,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(r);
verifyBeep();
+ assertTrue(r.isInterruptive());
}
@Test
@@ -418,6 +422,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
+ assertFalse(r.isInterruptive());
}
@Test
@@ -429,6 +434,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
verifyNeverBeep();
verifyNeverVibrate();
+ assertFalse(r.isInterruptive());
}
@Test
@@ -440,6 +446,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
verifyNeverBeep();
verifyNeverVibrate();
+ assertFalse(r.isInterruptive());
}
@Test
@@ -455,6 +462,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(r);
verifyBeepLooped();
verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt());
+ assertTrue(r.isInterruptive());
}
@Test
@@ -482,6 +490,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(r);
verifyNeverStopAudio();
+ assertTrue(r.isInterruptive());
}
@Test
@@ -494,6 +503,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(s);
verifyNeverStopAudio();
+ assertTrue(r.isInterruptive());
+ assertFalse(s.isInterruptive());
}
@Test
@@ -511,6 +522,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
// should not stop noise, since we no longer own it
mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
verifyNeverStopAudio();
+ assertTrue(other.isInterruptive());
}
@Test
@@ -535,11 +547,13 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
// set up internal state
mService.buzzBeepBlinkLocked(r);
+ assertTrue(r.isInterruptive());
Mockito.reset(mRingtonePlayer);
// quiet update should stop making noise
mService.buzzBeepBlinkLocked(s);
verifyStopAudio();
+ assertFalse(s.isInterruptive());
}
@Test
@@ -550,11 +564,13 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
// set up internal state
mService.buzzBeepBlinkLocked(r);
+ assertTrue(r.isInterruptive());
Mockito.reset(mRingtonePlayer);
// stop making noise - this is a weird corner case, but quiet should override once
mService.buzzBeepBlinkLocked(s);
verifyStopAudio();
+ assertFalse(s.isInterruptive());
}
@Test
@@ -570,6 +586,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
verify(mService, times(1)).playInCallNotification();
verifyNeverBeep(); // doesn't play normal beep
+ assertTrue(r.isInterruptive());
}
@Test
@@ -587,6 +604,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
verify(mVibrator, timeout(MAX_VIBRATION_DELAY).times(1)).vibrate(anyInt(), anyString(),
eq(effect), (AudioAttributes) anyObject());
+ assertTrue(r.isInterruptive());
}
@Test
@@ -603,6 +621,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
verifyNeverVibrate();
verifyBeepLooped();
+ assertTrue(r.isInterruptive());
}
@Test
@@ -621,6 +640,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
eq(FALLBACK_VIBRATION), (AudioAttributes) anyObject());
verify(mRingtonePlayer, never()).playAsync
(anyObject(), anyObject(), anyBoolean(), anyObject());
+ assertTrue(r.isInterruptive());
}
@Test
@@ -636,6 +656,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(r);
verifyDelayedVibrateLooped();
+ assertTrue(r.isInterruptive());
}
@Test
@@ -646,18 +667,20 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
verifyNeverBeep();
verifyVibrate();
+ assertTrue(r.isInterruptive());
}
@Test
- public void testInsistentVibrate() throws Exception {
+ public void testInsistentVibrate() {
NotificationRecord r = getInsistentBuzzyNotification();
mService.buzzBeepBlinkLocked(r);
verifyVibrateLooped();
+ assertTrue(r.isInterruptive());
}
@Test
- public void testVibrateTwice() throws Exception {
+ public void testVibrateTwice() {
NotificationRecord r = getBuzzyNotification();
// set up internal state
@@ -668,6 +691,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
r.isUpdate = true;
mService.buzzBeepBlinkLocked(r);
verifyVibrate();
+ assertTrue(r.isInterruptive());
}
@Test
@@ -677,6 +701,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(child);
verifyNeverBeep();
+ assertFalse(child.isInterruptive());
}
@Test
@@ -687,6 +712,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(summary);
verifyBeepLooped();
+ assertTrue(summary.isInterruptive());
}
@Test
@@ -696,6 +722,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(nonGroup);
verifyBeepLooped();
+ assertTrue(nonGroup.isInterruptive());
}
@Test
@@ -706,6 +733,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(summary);
verifyNeverBeep();
+ assertFalse(summary.isInterruptive());
}
@Test
@@ -715,6 +743,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(child);
verifyBeepLooped();
+ assertTrue(child.isInterruptive());
}
@Test
@@ -724,6 +753,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(nonGroup);
verifyBeepLooped();
+ assertTrue(nonGroup.isInterruptive());
}
@Test
@@ -733,6 +763,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(group);
verifyBeepLooped();
+ assertTrue(group.isInterruptive());
}
@Test
@@ -744,10 +775,12 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
// set up internal state
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mVibrator);
+ assertTrue(r.isInterruptive());
// update should not beep
mService.buzzBeepBlinkLocked(s);
verifyNeverVibrate();
+ assertFalse(s.isInterruptive());
}
@Test
@@ -759,6 +792,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(r);
verifyNeverStopVibrate();
+ assertTrue(r.isInterruptive());
}
@Test
@@ -771,6 +805,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(s);
verifyNeverStopVibrate();
+ assertTrue(r.isInterruptive());
+ assertFalse(s.isInterruptive());
}
@Test
@@ -788,6 +824,9 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
// should not stop vibrate, since we no longer own it
mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
verifyNeverStopVibrate();
+ assertTrue(r.isInterruptive());
+ assertTrue(other.isInterruptive());
+ assertFalse(s.isInterruptive());
}
@Test
@@ -802,10 +841,11 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
// should not stop noise, since it does not own it
mService.buzzBeepBlinkLocked(other);
verifyNeverStopVibrate();
+ assertFalse(other.isInterruptive());
}
@Test
- public void testQuietUpdateCancelsVibrate() throws Exception {
+ public void testQuietUpdateCancelsVibrate() {
NotificationRecord r = getBuzzyNotification();
NotificationRecord s = getQuietNotification();
s.isUpdate = true;
@@ -817,6 +857,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
// quiet update should stop making noise
mService.buzzBeepBlinkLocked(s);
verifyStopVibrate();
+ assertTrue(r.isInterruptive());
+ assertFalse(s.isInterruptive());
}
@Test
@@ -832,6 +874,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
// stop making noise - this is a weird corner case, but quiet should override once
mService.buzzBeepBlinkLocked(s);
verifyStopVibrate();
+ assertTrue(r.isInterruptive());
+ assertFalse(s.isInterruptive());
}
@Test
@@ -848,6 +892,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
// quiet update should stop making noise
mService.buzzBeepBlinkLocked(s);
verifyStopVibrate();
+ assertTrue(r.isInterruptive());
+ assertFalse(s.isInterruptive());
}
@Test
@@ -864,6 +910,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
+ assertFalse(r.isInterruptive());
}
@Test
@@ -874,6 +921,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
+ assertFalse(r.isInterruptive());
}
@Test
@@ -906,6 +954,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.buzzBeepBlinkLocked(r);
verifyNeverBeep();
+ assertFalse(r.isInterruptive());
}
@Test
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 3c371e56522..9be9f3fa254 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -989,6 +989,25 @@ public class UsageStatsService extends SystemService implements
mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
}
+ @Override
+ public void reportInterruptiveNotification(String packageName, String channelId,
+ int userId) {
+ if (packageName == null || channelId == null) {
+ Slog.w(TAG, "Event reported without a package name or a channel ID");
+ return;
+ }
+
+ UsageEvents.Event event = new UsageEvents.Event();
+ event.mPackage = packageName.intern();
+ event.mNotificationChannelId = channelId.intern();
+
+ // This will later be converted to system time.
+ event.mTimeStamp = SystemClock.elapsedRealtime();
+
+ event.mEventType = Event.NOTIFICATION_INTERRUPTION;
+ mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
+ }
+
@Override
public void reportShortcutUsage(String packageName, String shortcutId, int userId) {
if (packageName == null || shortcutId == null) {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 836eb318e4d..d9742825ac7 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -759,6 +759,8 @@ class UserUsageStatsService {
return "NOTIFICATION_SEEN";
case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
return "STANDBY_BUCKET_CHANGED";
+ case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
+ return "NOTIFICATION_INTERRUPTION";
default:
return "UNKNOWN";
}
--
GitLab
From 8f919514d51c769bec78210effcfd11fee1f798d Mon Sep 17 00:00:00 2001
From: Alan Viverette
Date: Mon, 12 Mar 2018 10:32:22 -0400
Subject: [PATCH 062/488] Fix resource directory references
Fixes: 74514647
Test: make
Change-Id: I47d65e56f7cdd3faa80c14d18e2e7767ca293ee4
---
packages/SettingsLib/common.mk | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index 3f9a0fd41c0..15b50d71929 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -34,21 +34,21 @@ LOCAL_RESOURCE_DIR += $(call my-dir)/res
# Include support-v7-appcompat, if not already included
ifeq (,$(findstring android-support-v7-appcompat,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v7/appcompat/res
+LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/appcompat/res
LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.appcompat
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat
endif
# Include support-v7-recyclerview, if not already included
ifeq (,$(findstring android-support-v7-recyclerview,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/v7/recyclerview/res
+LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/recyclerview/res
LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.recyclerview
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview
endif
# Include android-support-v7-preference, if not already included
ifeq (,$(findstring android-support-v7-preference,$(LOCAL_STATIC_JAVA_LIBRARIES)))
-LOCAL_RESOURCE_DIR += frameworks/support/preference/res
+LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/preference/res
LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.preference
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-preference
endif
--
GitLab
From 602bf1a8a88b64889c6c03c448bbcba12045e8a6 Mon Sep 17 00:00:00 2001
From: Bernardo Rufino
Date: Mon, 12 Mar 2018 12:17:40 +0000
Subject: [PATCH 063/488] Add tests for TransportStats and some refactor
Added units for http://ag/3709565. Some refactoring.
Test: m -j RunFrameworksServicesRoboTests
Bug: 72485465
Change-Id: Id75a4e0b96936580fd677041e091340b0fff8c1e
(cherry picked from commit cac3a7405997ab9783b537128107a71e6f5b75a2)
---
.../backup/transport/TransportStats.java | 66 +++++------
.../backup/transport/TransportStatsTest.java | 105 ++++++++++++++++++
2 files changed, 138 insertions(+), 33 deletions(-)
create mode 100644 services/robotests/src/com/android/server/backup/transport/TransportStatsTest.java
diff --git a/services/backup/java/com/android/server/backup/transport/TransportStats.java b/services/backup/java/com/android/server/backup/transport/TransportStats.java
index 4bef81aad10..bd84782122a 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportStats.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportStats.java
@@ -32,9 +32,12 @@ public class TransportStats {
void registerConnectionTime(ComponentName transportComponent, long timeMs) {
synchronized (mStatsLock) {
- mTransportStats
- .computeIfAbsent(transportComponent, name -> new Stats())
- .register(timeMs);
+ Stats stats = mTransportStats.get(transportComponent);
+ if (stats == null) {
+ stats = new Stats();
+ mTransportStats.put(transportComponent, stats);
+ }
+ stats.register(timeMs);
}
}
@@ -71,52 +74,49 @@ public class TransportStats {
private static void dumpStats(PrintWriter pw, String prefix, Stats stats) {
pw.println(
String.format(
- Locale.US, "%sAverage connection time: %.2f ms", prefix, stats.mAverage));
- pw.println(String.format(Locale.US, "%sMax connection time: %d ms", prefix, stats.mMax));
- pw.println(String.format(Locale.US, "%sMin connection time: %d ms", prefix, stats.mMin));
- pw.println(String.format(Locale.US, "%sNumber of connections: %d ", prefix, stats.mN));
+ Locale.US, "%sAverage connection time: %.2f ms", prefix, stats.average));
+ pw.println(String.format(Locale.US, "%sMax connection time: %d ms", prefix, stats.max));
+ pw.println(String.format(Locale.US, "%sMin connection time: %d ms", prefix, stats.min));
+ pw.println(String.format(Locale.US, "%sNumber of connections: %d ", prefix, stats.n));
}
public static final class Stats {
public static Stats merge(Stats a, Stats b) {
return new Stats(
- a.mN + b.mN,
- (a.mAverage * a.mN + b.mAverage * b.mN) / (a.mN + b.mN),
- Math.max(a.mMax, b.mMax),
- Math.min(a.mMin, b.mMin));
+ a.n + b.n,
+ (a.average * a.n + b.average * b.n) / (a.n + b.n),
+ Math.max(a.max, b.max),
+ Math.min(a.min, b.min));
}
- public int mN;
- public double mAverage;
- public long mMax;
- public long mMin;
+ public int n;
+ public double average;
+ public long max;
+ public long min;
public Stats() {
- mN = 0;
- mAverage = 0;
- mMax = 0;
- mMin = Long.MAX_VALUE;
+ n = 0;
+ average = 0;
+ max = 0;
+ min = Long.MAX_VALUE;
}
- private Stats(Stats original) {
- mN = original.mN;
- mAverage = original.mAverage;
- mMax = original.mMax;
- mMin = original.mMin;
+ private Stats(int n, double average, long max, long min) {
+ this.n = n;
+ this.average = average;
+ this.max = max;
+ this.min = min;
}
- private Stats(int n, double average, long max, long min) {
- mN = n;
- mAverage = average;
- mMax = max;
- mMin = min;
+ private Stats(Stats original) {
+ this(original.n, original.average, original.max, original.min);
}
private void register(long sample) {
- mAverage = (mAverage * mN + sample) / (mN + 1);
- mN++;
- mMax = Math.max(mMax, sample);
- mMin = Math.min(mMin, sample);
+ average = (average * n + sample) / (n + 1);
+ n++;
+ max = Math.max(max, sample);
+ min = Math.min(min, sample);
}
}
}
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportStatsTest.java b/services/robotests/src/com/android/server/backup/transport/TransportStatsTest.java
new file mode 100644
index 00000000000..322db85c4f4
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/transport/TransportStatsTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.transport;
+
+import static com.android.server.backup.testing.TransportData.backupTransport;
+import static com.android.server.backup.testing.TransportData.d2dTransport;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ComponentName;
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.backup.transport.TransportStats.Stats;
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderPackages({"com.android.server.backup"})
+@Presubmit
+public class TransportStatsTest {
+ private static final double TOLERANCE = 0.0001;
+
+ private TransportStats mTransportStats;
+ private ComponentName mTransportComponent1;
+ private ComponentName mTransportComponent2;
+
+ @Before
+ public void setUp() throws Exception {
+ mTransportStats = new TransportStats();
+ mTransportComponent1 = backupTransport().getTransportComponent();
+ mTransportComponent2 = d2dTransport().getTransportComponent();
+ }
+
+ @Test
+ public void testRegisterConnectionTime() {
+ mTransportStats.registerConnectionTime(mTransportComponent1, 50L);
+
+ Stats stats = mTransportStats.getStatsForTransport(mTransportComponent1);
+ assertThat(stats.average).isWithin(TOLERANCE).of(50);
+ assertThat(stats.max).isEqualTo(50L);
+ assertThat(stats.min).isEqualTo(50L);
+ assertThat(stats.n).isEqualTo(1);
+ }
+
+ @Test
+ public void testRegisterConnectionTime_whenHasAlreadyOneSample() {
+ mTransportStats.registerConnectionTime(mTransportComponent1, 50L);
+
+ mTransportStats.registerConnectionTime(mTransportComponent1, 100L);
+
+ Stats stats = mTransportStats.getStatsForTransport(mTransportComponent1);
+ assertThat(stats.average).isWithin(TOLERANCE).of(75);
+ assertThat(stats.max).isEqualTo(100L);
+ assertThat(stats.min).isEqualTo(50L);
+ assertThat(stats.n).isEqualTo(2);
+ }
+
+ @Test
+ public void testGetStatsForTransport() {
+ mTransportStats.registerConnectionTime(mTransportComponent1, 10L);
+ mTransportStats.registerConnectionTime(mTransportComponent2, 20L);
+
+ Stats stats = mTransportStats.getStatsForTransport(mTransportComponent1);
+
+ assertThat(stats.average).isWithin(TOLERANCE).of(10);
+ assertThat(stats.max).isEqualTo(10L);
+ assertThat(stats.min).isEqualTo(10L);
+ assertThat(stats.n).isEqualTo(1);
+ }
+
+ @Test
+ public void testMerge() {
+ mTransportStats.registerConnectionTime(mTransportComponent1, 10L);
+ mTransportStats.registerConnectionTime(mTransportComponent2, 20L);
+ Stats stats1 = mTransportStats.getStatsForTransport(mTransportComponent1);
+ Stats stats2 = mTransportStats.getStatsForTransport(mTransportComponent2);
+
+ Stats stats = Stats.merge(stats1, stats2);
+
+ assertThat(stats.average).isWithin(TOLERANCE).of(15);
+ assertThat(stats.max).isEqualTo(20L);
+ assertThat(stats.min).isEqualTo(10L);
+ assertThat(stats.n).isEqualTo(2);
+ }
+}
--
GitLab
From f9570f3fe556d8407c6e3334495d61655aee86a4 Mon Sep 17 00:00:00 2001
From: Jakub Pawlowski
Date: Wed, 21 Feb 2018 17:15:12 -0800
Subject: [PATCH 064/488] AudioService: Hearing Aid output management
This patch makes Hearing Aid output active/inactive when the connection
state, reported from Bluetooth stack is changed.
Bug: 64038649
Test: mm
Change-Id: Iaeee39febab3c340a77e02afe3e0a573fb9736f9
---
.../android/server/audio/AudioService.java | 216 ++++++++++++++++--
1 file changed, 191 insertions(+), 25 deletions(-)
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1e74263cb24..f577d09cdb9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -39,6 +39,7 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -256,6 +257,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
private static final int MSG_DISABLE_AUDIO_FOR_UID = 104;
+ private static final int MSG_SET_HEARING_AID_CONNECTION_STATE = 105;
// end of messages handled under wakelock
private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -265,6 +267,8 @@ public class AudioService extends IAudioService.Stub
// retry delay in case of failure to indicate system ready to AudioFlinger
private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
+ private static final int BT_HEARING_AID_GAIN_MIN = -128;
+
/** @see AudioSystemThread */
private AudioSystemThread mAudioSystemThread;
/** @see AudioHandler */
@@ -573,7 +577,7 @@ public class AudioService extends IAudioService.Stub
AudioSystem.DEVICE_OUT_HDMI_ARC |
AudioSystem.DEVICE_OUT_SPDIF |
AudioSystem.DEVICE_OUT_AUX_LINE;
- int mFullVolumeDevices = 0;
+ int mFullVolumeDevices = AudioSystem.DEVICE_OUT_HEARING_AID;
private final boolean mMonitorRotation;
@@ -590,6 +594,10 @@ public class AudioService extends IAudioService.Stub
private final MediaFocusControl mMediaFocusControl;
+ // Reference to BluetoothA2dp to query for volume.
+ private BluetoothHearingAid mHearingAid;
+ // lock always taken synchronized on mConnectedDevices
+ private final Object mHearingAidLock = new Object();
// Reference to BluetoothA2dp to query for AbsoluteVolume.
private BluetoothA2dp mA2dp;
// lock always taken synchronized on mConnectedDevices
@@ -849,6 +857,8 @@ public class AudioService extends IAudioService.Stub
if (adapter != null) {
adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
BluetoothProfile.A2DP);
+ adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
+ BluetoothProfile.HEARING_AID);
}
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
@@ -1607,6 +1617,20 @@ public class AudioService extends IAudioService.Stub
}
}
+ // Check if volume update should be send to Hearing Aid
+ if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
+ synchronized (mHearingAidLock) {
+ if (mHearingAid != null) {
+ //hearing aid expect volume value in range -128dB to 0dB
+ int gainDB = (int)AudioSystem.getStreamVolumeDB(streamType, newIndex/10,
+ AudioSystem.DEVICE_OUT_HEARING_AID);
+ if (gainDB < BT_HEARING_AID_GAIN_MIN)
+ gainDB = BT_HEARING_AID_GAIN_MIN;
+ mHearingAid.setVolume(gainDB);
+ }
+ }
+ }
+
// Check if volume update should be sent to Hdmi system audio.
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
@@ -1852,6 +1876,19 @@ public class AudioService extends IAudioService.Stub
}
}
+ if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
+ synchronized (mHearingAidLock) {
+ if (mHearingAid != null) {
+ //hearing aid expect volume value in range -128dB to 0dB
+ int gainDB = (int)AudioSystem.getStreamVolumeDB(streamType, index/10, AudioSystem.DEVICE_OUT_HEARING_AID);
+ if (gainDB < BT_HEARING_AID_GAIN_MIN)
+ gainDB = BT_HEARING_AID_GAIN_MIN;
+ mHearingAid.setVolume(gainDB);
+
+ }
+ }
+ }
+
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
}
@@ -3609,6 +3646,30 @@ public class AudioService extends IAudioService.Stub
}
break;
+ case BluetoothProfile.HEARING_AID:
+ synchronized (mConnectedDevices) {
+ synchronized (mHearingAidLock) {
+ mHearingAid = (BluetoothHearingAid) proxy;
+ deviceList = mHearingAid.getConnectedDevices();
+ if (deviceList.size() > 0) {
+ btDevice = deviceList.get(0);
+ int state = mHearingAid.getConnectionState(btDevice);
+ int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
+ int delay = checkSendBecomingNoisyIntent(
+ AudioSystem.DEVICE_OUT_HEARING_AID, intState,
+ AudioSystem.DEVICE_NONE);
+ queueMsgUnderWakeLock(mAudioHandler,
+ MSG_SET_HEARING_AID_CONNECTION_STATE,
+ state,
+ 0 /* arg2 unused */,
+ btDevice,
+ delay);
+ }
+ }
+ }
+
+ break;
+
default:
break;
}
@@ -3628,6 +3689,10 @@ public class AudioService extends IAudioService.Stub
disconnectHeadset();
break;
+ case BluetoothProfile.HEARING_AID:
+ disconnectHearingAid();
+ break;
+
default:
break;
}
@@ -3638,6 +3703,7 @@ public class AudioService extends IAudioService.Stub
disconnectA2dp();
disconnectA2dpSink();
disconnectHeadset();
+ disconnectHearingAid();
}
void disconnectA2dp() {
@@ -3689,6 +3755,29 @@ public class AudioService extends IAudioService.Stub
}
}
+ void disconnectHearingAid() {
+ synchronized (mConnectedDevices) {
+ synchronized (mHearingAidLock) {
+ ArraySet toRemove = null;
+ // Disconnect ALL DEVICE_OUT_HEARING_AID devices
+ for (int i = 0; i < mConnectedDevices.size(); i++) {
+ DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
+ if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
+ toRemove = toRemove != null ? toRemove : new ArraySet();
+ toRemove.add(deviceSpec.mDeviceAddress);
+ }
+ }
+ if (toRemove != null) {
+ int delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_HEARING_AID,
+ 0, AudioSystem.DEVICE_NONE);
+ for (int i = 0; i < toRemove.size(); i++) {
+ makeHearingAidDeviceUnavailable(toRemove.valueAt(i) /*, delay*/);
+ }
+ }
+ }
+ }
+ }
+
private void onCheckMusicActive(String caller) {
synchronized (mSafeMediaVolumeState) {
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
@@ -4200,7 +4289,8 @@ public class AudioService extends IAudioService.Stub
handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
- msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
+ msg == MSG_SET_A2DP_SINK_CONNECTION_STATE ||
+ msg == MSG_SET_HEARING_AID_CONNECTION_STATE) {
mLastDeviceConnectMsgTime = time;
}
}
@@ -4303,6 +4393,33 @@ public class AudioService extends IAudioService.Stub
@Override
public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state)
{
+ Log.i(TAG, "setBluetoothHearingAidDeviceConnectionState");
+
+ setBluetoothHearingAidDeviceConnectionState(
+ device, state, false /* suppressNoisyIntent */, AudioSystem.DEVICE_NONE);
+ }
+
+ public int setBluetoothHearingAidDeviceConnectionState(
+ BluetoothDevice device, int state, boolean suppressNoisyIntent,
+ int musicDevice)
+ {
+ int delay;
+ synchronized (mConnectedDevices) {
+ if (!suppressNoisyIntent) {
+ int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
+ delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_HEARING_AID,
+ intState, musicDevice);
+ } else {
+ delay = 0;
+ }
+ queueMsgUnderWakeLock(mAudioHandler,
+ MSG_SET_HEARING_AID_CONNECTION_STATE,
+ state,
+ 0 /* arg2 unused */,
+ device,
+ delay);
+ }
+ return delay;
}
public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
@@ -5244,6 +5361,11 @@ public class AudioService extends IAudioService.Stub
mAudioEventWakeLock.release();
break;
+ case MSG_SET_HEARING_AID_CONNECTION_STATE:
+ onSetHearingAidConnectionState((BluetoothDevice)msg.obj, msg.arg1);
+ mAudioEventWakeLock.release();
+ break;
+
case MSG_A2DP_DEVICE_CONFIG_CHANGE:
onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj);
mAudioEventWakeLock.release();
@@ -5436,14 +5558,8 @@ public class AudioService extends IAudioService.Stub
AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
mConnectedDevices.remove(
makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
- synchronized (mCurAudioRoutes) {
- // Remove A2DP routes as well
- if (mCurAudioRoutes.bluetoothName != null) {
- mCurAudioRoutes.bluetoothName = null;
- sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
- SENDMSG_NOOP, 0, 0, null, 0);
- }
- }
+ // Remove A2DP routes as well
+ setCurrentAudioRouteName(null);
}
// must be called synchronized on mConnectedDevices
@@ -5478,6 +5594,28 @@ public class AudioService extends IAudioService.Stub
makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
}
+ // must be called synchronized on mConnectedDevices
+ private void makeHearingAidDeviceAvailable(String address, String name, String eventSource) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
+ AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
+ mConnectedDevices.put(
+ makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
+ new DeviceListSpec(AudioSystem.DEVICE_OUT_HEARING_AID, name,
+ address));
+ sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
+ AudioSystem.DEVICE_OUT_HEARING_AID, 0, null, 0);
+ }
+
+ // must be called synchronized on mConnectedDevices
+ private void makeHearingAidDeviceUnavailable(String address) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
+ mConnectedDevices.remove(
+ makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
+ // Remove Hearing Aid routes as well
+ setCurrentAudioRouteName(null);
+ }
+
// must be called synchronized on mConnectedDevices
private void cancelA2dpDeviceTimeout() {
mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
@@ -5519,13 +5657,7 @@ public class AudioService extends IAudioService.Stub
} else {
makeA2dpDeviceUnavailableNow(address);
}
- synchronized (mCurAudioRoutes) {
- if (mCurAudioRoutes.bluetoothName != null) {
- mCurAudioRoutes.bluetoothName = null;
- sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
- SENDMSG_NOOP, 0, 0, null, 0);
- }
- }
+ setCurrentAudioRouteName(null);
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
if (btDevice.isBluetoothDock()) {
// this could be a reconnection after a transient disconnection
@@ -5541,14 +5673,7 @@ public class AudioService extends IAudioService.Stub
}
makeA2dpDeviceAvailable(address, btDevice.getName(),
"onSetA2dpSinkConnectionState");
- synchronized (mCurAudioRoutes) {
- String name = btDevice.getAliasName();
- if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
- mCurAudioRoutes.bluetoothName = name;
- sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
- SENDMSG_NOOP, 0, 0, null, 0);
- }
- }
+ setCurrentAudioRouteName(btDevice.getAliasName());
}
}
}
@@ -5579,6 +5704,46 @@ public class AudioService extends IAudioService.Stub
}
}
+ private void onSetHearingAidConnectionState(BluetoothDevice btDevice, int state)
+ {
+ if (DEBUG_DEVICES) {
+ Log.d(TAG, "onSetHearingAidConnectionState btDevice=" + btDevice+", state=" + state);
+ }
+ if (btDevice == null) {
+ return;
+ }
+ String address = btDevice.getAddress();
+ if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+ address = "";
+ }
+
+ synchronized (mConnectedDevices) {
+ final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID,
+ btDevice.getAddress());
+ final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+ boolean isConnected = deviceSpec != null;
+
+ if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
+ makeHearingAidDeviceUnavailable(address);
+ setCurrentAudioRouteName(null);
+ } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
+ makeHearingAidDeviceAvailable(address, btDevice.getName(),
+ "onSetHearingAidConnectionState");
+ setCurrentAudioRouteName(btDevice.getAliasName());
+ }
+ }
+ }
+
+ private void setCurrentAudioRouteName(String name){
+ synchronized (mCurAudioRoutes) {
+ if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
+ mCurAudioRoutes.bluetoothName = name;
+ sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+ SENDMSG_NOOP, 0, 0, null, 0);
+ }
+ }
+ }
+
private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
{
if (DEBUG_DEVICES) {
@@ -5714,6 +5879,7 @@ public class AudioService extends IAudioService.Stub
if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
+ mAudioHandler.hasMessages(MSG_SET_HEARING_AID_CONNECTION_STATE) ||
mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
synchronized (mLastDeviceConnectMsgTime) {
long time = SystemClock.uptimeMillis();
--
GitLab
From 476edc8148a4b13b81062b51e37de7f6cabb1286 Mon Sep 17 00:00:00 2001
From: Bryce Lee
Date: Mon, 12 Mar 2018 10:06:23 -0700
Subject: [PATCH 065/488] Update documentation for Activity#onCreate.
The current description incorrectly states #onDestroy will be called
immediately when invoking #finish during #onCreate.
Change-Id: I816a54457d7aca0b40feac9a5656d94f7e712c76
Fixes: 69144863
Test: comment update.
---
core/java/android/app/Activity.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 99c5d2b9a92..56877809416 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -995,9 +995,9 @@ public class Activity extends ContextThemeWrapper
* cursors for data being displayed, etc.
*
*
You can call {@link #finish} from within this function, in
- * which case onDestroy() will be immediately called without any of the rest
- * of the activity lifecycle ({@link #onStart}, {@link #onResume},
- * {@link #onPause}, etc) executing.
+ * which case onDestroy() will be immediately called after {@link #onCreate} without any of the
+ * rest of the activity lifecycle ({@link #onStart}, {@link #onResume}, {@link #onPause}, etc)
+ * executing.
*
*
Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
--
GitLab
From 1c7eb0c8eb156c4656f2d3e1b97929797e4e7ec9 Mon Sep 17 00:00:00 2001
From: Felipe Leme
Date: Fri, 9 Mar 2018 14:13:18 -0800
Subject: [PATCH 066/488] Moved urlBarResourceId from autofill service manifest
to whitelist settings.
The manifest attribute is still public as it might have been used by autofill
services deployed against P DP1; it will be removed after the next developer
previs is branched out. We also need to assumie a default value for the buttons
if not specified by settings, but that will be done in a separate change so it
can be easily reverted.
Also implemented support for multiple buttons, and added unit tests.
Test: atest CtsAutoFillServiceTestCases:VirtualContainerActivityCompatModeTest \
CtsAutoFillServiceTestCases:VirtualContainerActivityTest \
FrameworksServicesTests:AutofillManagerServiceTest
Bug: 74445943
Bug: 72811561
Fixes: 73786629
Change-Id: I066ecf40fde2c5318dd8633a659fca8b7af8aecd
---
core/java/android/provider/Settings.java | 9 +-
.../service/autofill/AutofillServiceInfo.java | 38 ++---
core/res/res/values/attrs.xml | 4 +-
core/res/res/values/public.xml | 1 +
.../autofill/AutofillManagerService.java | 142 +++++++++++++++---
.../autofill/AutofillManagerServiceImpl.java | 22 ++-
.../com/android/server/autofill/Helper.java | 12 +-
.../com/android/server/autofill/Session.java | 10 +-
services/tests/servicestests/Android.mk | 1 +
.../autofill/AutofillManagerServiceTest.java | 94 ++++++++++++
10 files changed, 261 insertions(+), 72 deletions(-)
create mode 100644 services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bd29d2de7ba..2f4e6212c4c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11483,7 +11483,14 @@ public final class Settings {
/**
* The packages whitelisted to be run in autofill compatibility mode. The list
- * of packages is ":" colon delimited.
+ * of packages is {@code ":"} colon delimited, and each entry has the name of the
+ * package and an optional list of url bar resource ids (the list is delimited by
+ * brackets&mdash{@code [} and {@code ]}&mdash and is also comma delimited).
+ *
+ *
For example, a list with 3 packages {@code p1}, {@code p2}, and {@code p3}, where
+ * package {@code p1} have one id ({@code url_bar}, {@code p2} has none, and {@code p3 }
+ * have 2 ids {@code url_foo} and {@code url_bas}) would be
+ * {@code p1[url_bar]:p2:p3[url_foo,url_bas]}
*
* @hide
*/
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index 70c4ec07ee4..de234559d53 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -32,7 +32,6 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.Pair;
import android.util.Xml;
import com.android.internal.R;
@@ -79,7 +78,7 @@ public final class AutofillServiceInfo {
private final String mSettingsActivity;
@Nullable
- private final ArrayMap> mCompatibilityPackages;
+ private final ArrayMap mCompatibilityPackages;
public AutofillServiceInfo(Context context, ComponentName comp, int userHandle)
throws PackageManager.NameNotFoundException {
@@ -117,7 +116,7 @@ public final class AutofillServiceInfo {
}
String settingsActivity = null;
- ArrayMap> compatibilityPackages = null;
+ ArrayMap compatibilityPackages = null;
try {
final Resources resources = context.getPackageManager().getResourcesForApplication(
@@ -153,10 +152,9 @@ public final class AutofillServiceInfo {
mCompatibilityPackages = compatibilityPackages;
}
- private ArrayMap> parseCompatibilityPackages(XmlPullParser parser,
- Resources resources)
- throws IOException, XmlPullParserException {
- ArrayMap> compatibilityPackages = null;
+ private ArrayMap parseCompatibilityPackages(XmlPullParser parser,
+ Resources resources) throws IOException, XmlPullParserException {
+ ArrayMap compatibilityPackages = null;
final int outerDepth = parser.getDepth();
int type;
@@ -200,13 +198,18 @@ public final class AutofillServiceInfo {
} else {
maxVersionCode = Long.MAX_VALUE;
}
- final String urlBarResourceId = cpAttributes.getString(
- R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId);
+ if (true) { // TODO(b/74445943): remove block after P DP2 is branched
+ final String urlBarResourceId = cpAttributes.getString(
+ R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId);
+ if (urlBarResourceId != null) {
+ Log.e(TAG, "Service is using deprecated attribute 'urlBarResourceId'");
+ }
+ }
if (compatibilityPackages == null) {
compatibilityPackages = new ArrayMap<>();
}
- compatibilityPackages.put(name, new Pair<>(maxVersionCode, urlBarResourceId));
+ compatibilityPackages.put(name, maxVersionCode);
} finally {
XmlUtils.skipCurrentTag(parser);
if (cpAttributes != null) {
@@ -228,23 +231,10 @@ public final class AutofillServiceInfo {
return mSettingsActivity;
}
- public ArrayMap> getCompatibilityPackages() {
+ public ArrayMap getCompatibilityPackages() {
return mCompatibilityPackages;
}
- /**
- * Gets the resource id of the URL bar for a package. Used in compat mode
- */
- // TODO: return a list of strings instead
- @Nullable
- public String getUrlBarResourceId(String packageName) {
- if (mCompatibilityPackages == null) {
- return null;
- }
- final Pair pair = mCompatibilityPackages.get(packageName);
- return pair == null ? null : pair.second;
- }
-
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 021e88ea609..6d23fab54ae 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7978,9 +7978,7 @@
android.content.pm.PackageInfo#getLongVersionCode()} for the target package.
-->
-
+
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7d5d1ba1366..2c0deedc435 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2869,6 +2869,7 @@
+
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 266b2d79199..8a66414358a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -59,9 +59,7 @@ import android.service.autofill.UserData;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.LocalLog;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -73,6 +71,7 @@ import android.view.autofill.IAutoFillManager;
import android.view.autofill.IAutoFillManagerClient;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.IResultReceiver;
@@ -88,8 +87,8 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
-import java.util.Set;
/**
* Entry point service for autofill management.
@@ -105,6 +104,9 @@ public final class AutofillManagerService extends SystemService {
static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
private static final char COMPAT_PACKAGE_DELIMITER = ':';
+ private static final char COMPAT_PACKAGE_URL_IDS_DELIMITER = ',';
+ private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN = '[';
+ private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_END = ']';
private final Context mContext;
private final AutoFillUI mUi;
@@ -326,7 +328,7 @@ public final class AutofillManagerService extends SystemService {
if (service == null) {
service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory,
mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi,
- mDisabledUsers.get(resolvedUserId));
+ mAutofillCompatState, mDisabledUsers.get(resolvedUserId));
mServicesCache.put(userId, service);
addCompatibilityModeRequestsLocked(service, userId);
}
@@ -544,23 +546,24 @@ public final class AutofillManagerService extends SystemService {
private void addCompatibilityModeRequestsLocked(@NonNull AutofillManagerServiceImpl service
, int userId) {
mAutofillCompatState.reset();
- final ArrayMap> compatPackages =
+ final ArrayMap compatPackages =
service.getCompatibilityPackagesLocked();
if (compatPackages == null || compatPackages.isEmpty()) {
return;
}
- final Set whiteListedPackages = getWhitelistedCompatModePackages();
+
+ final Map whiteListedPackages = getWhitelistedCompatModePackages();
final int compatPackageCount = compatPackages.size();
for (int i = 0; i < compatPackageCount; i++) {
final String packageName = compatPackages.keyAt(i);
- if (whiteListedPackages == null || !whiteListedPackages.contains(packageName)) {
+ if (whiteListedPackages == null || !whiteListedPackages.containsKey(packageName)) {
Slog.w(TAG, "Ignoring not whitelisted compat package " + packageName);
continue;
}
- final Long maxVersionCode = compatPackages.valueAt(i).first;
+ final Long maxVersionCode = compatPackages.valueAt(i);
if (maxVersionCode != null) {
mAutofillCompatState.addCompatibilityModeRequest(packageName,
- maxVersionCode, userId);
+ maxVersionCode, whiteListedPackages.get(packageName), userId);
}
}
}
@@ -571,16 +574,60 @@ public final class AutofillManagerService extends SystemService {
Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
}
- private @Nullable Set getWhitelistedCompatModePackages() {
- final String compatPackagesSetting = getWhitelistedCompatModePackagesFromSettings();
- if (TextUtils.isEmpty(compatPackagesSetting)) {
+ @Nullable
+ private Map getWhitelistedCompatModePackages() {
+ return getWhitelistedCompatModePackages(getWhitelistedCompatModePackagesFromSettings());
+ }
+
+ @Nullable
+ @VisibleForTesting
+ static Map getWhitelistedCompatModePackages(String setting) {
+ if (TextUtils.isEmpty(setting)) {
return null;
}
- final Set compatPackages = new ArraySet<>();
+
+ final ArrayMap compatPackages = new ArrayMap<>();
final SimpleStringSplitter splitter = new SimpleStringSplitter(COMPAT_PACKAGE_DELIMITER);
- splitter.setString(compatPackagesSetting);
+ splitter.setString(setting);
while (splitter.hasNext()) {
- compatPackages.add(splitter.next());
+ final String packageBlock = splitter.next();
+ final int urlBlockIndex = packageBlock.indexOf(COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN);
+ final String packageName;
+ final List urlBarIds;
+ if (urlBlockIndex == -1) {
+ packageName = packageBlock;
+ urlBarIds = null;
+ } else {
+ if (packageBlock.charAt(packageBlock.length() - 1)
+ != COMPAT_PACKAGE_URL_IDS_BLOCK_END) {
+ Slog.w(TAG, "Ignoring entry '" + packageBlock + "' on '" + setting
+ + "'because it does not end on '" + COMPAT_PACKAGE_URL_IDS_BLOCK_END +
+ "'");
+ continue;
+ }
+ packageName = packageBlock.substring(0, urlBlockIndex);
+ urlBarIds = new ArrayList<>();
+ final String urlBarIdsBlock =
+ packageBlock.substring(urlBlockIndex + 1, packageBlock.length() - 1);
+ if (sVerbose) {
+ Slog.v(TAG, "pkg:" + packageName + ": block:" + packageBlock + ": urls:"
+ + urlBarIds + ": block:" + urlBarIdsBlock + ":");
+ }
+ final SimpleStringSplitter splitter2 =
+ new SimpleStringSplitter(COMPAT_PACKAGE_URL_IDS_DELIMITER);
+ splitter2.setString(urlBarIdsBlock);
+ while (splitter2.hasNext()) {
+ final String urlBarId = splitter2.next();
+ urlBarIds.add(urlBarId);
+ }
+ }
+ if (urlBarIds == null) {
+ compatPackages.put(packageName, null);
+ } else {
+ final String[] urlBarIdsArray = new String[urlBarIds.size()];
+ urlBarIds.toArray(urlBarIdsArray);
+ compatPackages.put(packageName, urlBarIdsArray);
+ }
}
return compatPackages;
}
@@ -598,13 +645,41 @@ public final class AutofillManagerService extends SystemService {
return mAutofillCompatState.isCompatibilityModeRequested(
packageName, versionCode, userId);
}
+
+ }
+
+ /**
+ * Compatibility mode metadata per package.
+ */
+ private static final class PackageCompatState {
+ private final long maxVersionCode;
+ private final String[] urlBarResourceIds;
+
+ PackageCompatState(long maxVersionCode, String[] urlBarResourceIds) {
+ this.maxVersionCode = maxVersionCode;
+ this.urlBarResourceIds = urlBarResourceIds;
+ }
+
+ @Override
+ public String toString() {
+ return "PackageCompatState: [maxVersionCode=" + maxVersionCode
+ + ", urlBarResourceIds=" + Arrays.toString(urlBarResourceIds) + "]";
+ }
}
- private static final class AutofillCompatState {
+ /**
+ * Compatibility mode metadata associated with all services.
+ *
+ *
This object is defined here instead of on each {@link AutofillManagerServiceImpl} because
+ * it cannot hold a lock on the main lock when
+ * {@link AutofillCompatState#isCompatibilityModeRequested(String, long, int)} is called by
+ * external services.
+ */
+ static final class AutofillCompatState {
private final Object mLock = new Object();
@GuardedBy("mLock")
- private SparseArray> mUserSpecs;
+ private SparseArray> mUserSpecs;
boolean isCompatibilityModeRequested(@NonNull String packageName,
long versionCode, @UserIdInt int userId) {
@@ -612,30 +687,49 @@ public final class AutofillManagerService extends SystemService {
if (mUserSpecs == null) {
return false;
}
- final ArrayMap userSpec = mUserSpecs.get(userId);
+ final ArrayMap userSpec = mUserSpecs.get(userId);
if (userSpec == null) {
return false;
}
- final Long maxVersionCode = userSpec.get(packageName);
- if (maxVersionCode == null) {
+ final PackageCompatState metadata = userSpec.get(packageName);
+ if (metadata == null) {
return false;
}
- return versionCode <= maxVersionCode;
+ return versionCode <= metadata.maxVersionCode;
+ }
+ }
+
+ @Nullable
+ String[] getUrlBarResourceIds(@NonNull String packageName, @UserIdInt int userId) {
+ synchronized (mLock) {
+ if (mUserSpecs == null) {
+ return null;
+ }
+ final ArrayMap userSpec = mUserSpecs.get(userId);
+ if (userSpec == null) {
+ return null;
+ }
+ final PackageCompatState metadata = userSpec.get(packageName);
+ if (metadata == null) {
+ return null;
+ }
+ return metadata.urlBarResourceIds;
}
}
void addCompatibilityModeRequest(@NonNull String packageName,
- long versionCode, @UserIdInt int userId) {
+ long versionCode, @Nullable String[] urlBarResourceIds, @UserIdInt int userId) {
synchronized (mLock) {
if (mUserSpecs == null) {
mUserSpecs = new SparseArray<>();
}
- ArrayMap userSpec = mUserSpecs.get(userId);
+ ArrayMap userSpec = mUserSpecs.get(userId);
if (userSpec == null) {
userSpec = new ArrayMap<>();
mUserSpecs.put(userId, userSpec);
}
- userSpec.put(packageName, versionCode);
+ userSpec.put(packageName,
+ new PackageCompatState(versionCode, urlBarResourceIds));
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 8622dbe820a..54ea3ba4546 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -64,7 +64,6 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.LocalLog;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -78,12 +77,12 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.LocalServices;
+import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
import com.android.server.autofill.ui.AutoFillUI;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
import java.util.Random;
/**
@@ -164,12 +163,15 @@ final class AutofillManagerServiceImpl {
@GuardedBy("mLock")
private FillEventHistory mEventHistory;
+ /** Shared instance, doesn't need to be logged */
+ private final AutofillCompatState mAutofillCompatState;
+
/** When was {@link PruneTask} last executed? */
private long mLastPrune = 0;
AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
- boolean disabled) {
+ AutofillCompatState autofillCompatState, boolean disabled) {
mContext = context;
mLock = lock;
mRequestsHistory = requestsHistory;
@@ -178,6 +180,7 @@ final class AutofillManagerServiceImpl {
mUserId = userId;
mUi = ui;
mFieldClassificationStrategy = new FieldClassificationStrategy(context, userId);
+ mAutofillCompatState = autofillCompatState;
updateLocked(disabled);
}
@@ -208,14 +211,9 @@ final class AutofillManagerServiceImpl {
}
- @GuardedBy("mLock")
@Nullable
- String getUrlBarResourceIdForCompatModeLocked(@NonNull String packageName) {
- if (mInfo == null) {
- Slog.w(TAG, "getUrlBarResourceIdForCompatModeLocked(): no mInfo");
- return null;
- }
- return mInfo.getUrlBarResourceId(packageName);
+ String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) {
+ return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId);
}
@Nullable
@@ -893,7 +891,7 @@ final class AutofillManagerServiceImpl {
pw.print(prefix); pw.print("Field classification enabled: ");
pw.println(isFieldClassificationEnabledLocked());
pw.print(prefix); pw.print("Compat pkgs: ");
- final ArrayMap> compatPkgs = getCompatibilityPackagesLocked();
+ final ArrayMap compatPkgs = getCompatibilityPackagesLocked();
if (compatPkgs == null) {
pw.println("N/A");
} else {
@@ -1022,7 +1020,7 @@ final class AutofillManagerServiceImpl {
}
@GuardedBy("mLock")
- @Nullable ArrayMap> getCompatibilityPackagesLocked() {
+ @Nullable ArrayMap getCompatibilityPackagesLocked() {
if (mInfo != null) {
return mInfo.getCompatibilityPackages();
}
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 232dfdcf045..5c41f3f869c 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -30,6 +30,7 @@ import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.ArrayUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -168,21 +169,24 @@ public final class Helper {
/**
* Sanitize the {@code webDomain} property of the URL bar node on compat mode.
+ *
+ * @param structure Assist structure
+ * @param urlBarIds list of ids; only the first id found will be sanitized.
*/
public static void sanitizeUrlBar(@NonNull AssistStructure structure,
- @NonNull String urlBarId) {
+ @NonNull String[] urlBarIds) {
final ViewNode urlBarNode = findViewNode(structure, (node) -> {
- return urlBarId.equals(node.getIdEntry());
+ return ArrayUtils.contains(urlBarIds, node.getIdEntry());
});
if (urlBarNode != null) {
final String domain = urlBarNode.getText().toString();
if (domain.isEmpty()) {
- if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarId);
+ if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarNode.getIdEntry());
return;
}
urlBarNode.setWebDomain(domain);
if (sDebug) {
- Slog.d(TAG, "sanitizeUrlBar(): id=" + urlBarId + ", domain="
+ Slog.d(TAG, "sanitizeUrlBar(): id=" + urlBarNode.getIdEntry() + ", domain="
+ urlBarNode.getWebDomain());
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 4abf0f8e8f1..26598a2e24b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -274,11 +274,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
if (mCompatMode) {
// Sanitize URL bar, if needed
- final String urlBarId = mService.getUrlBarResourceIdForCompatModeLocked(
+ final String[] urlBarIds = mService.getUrlBarResourceIdsForCompatMode(
mComponentName.getPackageName());
- if (sDebug) Slog.d(TAG, "url_bar in compat mode: " + urlBarId);
- if (urlBarId != null) {
- Helper.sanitizeUrlBar(structure, urlBarId);
+ if (sDebug) {
+ Slog.d(TAG, "url_bars in compat mode: " + Arrays.toString(urlBarIds));
+ }
+ if (urlBarIds != null) {
+ Helper.sanitizeUrlBar(structure, urlBarIds);
}
}
structure.sanitizeForParceling(true);
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 356e64b5dd7..0ca0a1a104c 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -15,6 +15,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
frameworks-base-testutils \
services.accessibility \
services.appwidget \
+ services.autofill \
services.backup \
services.core \
services.devicepolicy \
diff --git a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
new file mode 100644
index 00000000000..d5a28f6b1d7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.autofill;
+
+import static com.android.server.autofill.AutofillManagerService.getWhitelistedCompatModePackages;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public class AutofillManagerServiceTest {
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_null() {
+ assertThat(getWhitelistedCompatModePackages(null)).isNull();
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_empty() {
+ assertThat(getWhitelistedCompatModePackages("")).isNull();
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_onePackageNoUrls() {
+ assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package"))
+ .containsExactly("one_is_the_loniest_package", null);
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_onePackageMissingEndDelimiter() {
+ assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package[")).isEmpty();
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_onePackageOneUrl() {
+ final Map result =
+ getWhitelistedCompatModePackages("one_is_the_loniest_package[url]");
+ assertThat(result).hasSize(1);
+ assertThat(result.get("one_is_the_loniest_package")).asList().containsExactly("url");
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_onePackageMultipleUrls() {
+ final Map result =
+ getWhitelistedCompatModePackages("one_is_the_loniest_package[4,5,8,15,16,23,42]");
+ assertThat(result).hasSize(1);
+ assertThat(result.get("one_is_the_loniest_package")).asList()
+ .containsExactly("4", "5", "8", "15", "16", "23", "42");
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_multiplePackagesOneInvalid() {
+ final Map result = getWhitelistedCompatModePackages("one:two[");
+ assertThat(result).hasSize(1);
+ assertThat(result.get("one")).isNull();
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_multiplePackagesMultipleUrls() {
+ final Map result =
+ getWhitelistedCompatModePackages("p1[p1u1]:p2:p3[p3u1,p3u2]");
+ assertThat(result).hasSize(3);
+ assertThat(result.get("p1")).asList().containsExactly("p1u1");
+ assertThat(result.get("p2")).isNull();
+ assertThat(result.get("p3")).asList().containsExactly("p3u1", "p3u2");
+ }
+
+ @Test
+ public void testGetWhitelistedCompatModePackages_threePackagesOneInvalid() {
+ final Map result =
+ getWhitelistedCompatModePackages("p1[p1u1]:p2[:p3[p3u1,p3u2]");
+ assertThat(result).hasSize(2);
+ assertThat(result.get("p1")).asList().containsExactly("p1u1");
+ assertThat(result.get("p3")).asList().containsExactly("p3u1", "p3u2");
+ }
+}
--
GitLab
From 6a4fa0ec183e20c32e7816f5475e72fa9126356c Mon Sep 17 00:00:00 2001
From: Adrian Roos
Date: Mon, 5 Mar 2018 19:50:16 +0100
Subject: [PATCH 067/488] DisplayCutout: Support more than one cutout
Also makes API more restrictive. Also moves window manager specific
logic out of the framework. Also fixes SystemUI such that it can properly
deal with more than one cutout.
Bug: 74195186
Test: atest DisplayCutoutTest WmDisplayCutoutTest DisplayContentTests WindowFrameTests
Change-Id: Ib7b89e119ce2d3961687579bb81eadce1159a600
---
api/current.txt | 6 +-
core/java/android/view/DisplayCutout.java | 240 +++++++++---------
core/java/android/view/WindowManager.java | 28 +-
core/res/res/values/attrs.xml | 15 +-
core/tests/coretests/res/values/styles.xml | 4 +-
.../src/android/view/DisplayCutoutTest.java | 114 +--------
.../internal/policy/PhoneWindowTest.java | 7 +-
.../android/systemui/ScreenDecorations.java | 53 +++-
.../phone/KeyguardStatusBarView.java | 11 +-
.../statusbar/phone/PhoneStatusBarView.java | 11 +-
.../server/display/LocalDisplayAdapter.java | 3 +-
.../server/policy/PhoneWindowManager.java | 3 +-
.../server/policy/WindowManagerPolicy.java | 5 +-
.../com/android/server/wm/DisplayContent.java | 33 ++-
.../com/android/server/wm/DisplayFrames.java | 19 +-
.../wm/DockedStackDividerController.java | 4 +-
.../server/wm/WindowManagerService.java | 6 +-
.../com/android/server/wm/WindowState.java | 13 +-
.../server/wm/utils/WmDisplayCutout.java | 173 +++++++++++++
.../server/policy/FakeWindowState.java | 6 +-
.../policy/PhoneWindowManagerTestBase.java | 20 +-
.../server/wm/DisplayContentTests.java | 17 +-
.../android/server/wm/WindowFrameTests.java | 55 ++--
.../server/wm/utils/WmDisplayCutoutTest.java | 157 ++++++++++++
24 files changed, 677 insertions(+), 326 deletions(-)
create mode 100644 services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
create mode 100644 services/tests/servicestests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
diff --git a/api/current.txt b/api/current.txt
index c2f1bc58bf6..050afb62148 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -46618,8 +46618,8 @@ package android.view {
}
public final class DisplayCutout {
- ctor public DisplayCutout(android.graphics.Rect, android.graphics.Region);
- method public android.graphics.Region getBounds();
+ ctor public DisplayCutout(android.graphics.Rect, java.util.List);
+ method public java.util.List getBoundingRects();
method public int getSafeInsetBottom();
method public int getSafeInsetLeft();
method public int getSafeInsetRight();
@@ -49693,9 +49693,9 @@ package android.view {
field public static final int LAST_SUB_WINDOW = 1999; // 0x7cf
field public static final int LAST_SYSTEM_WINDOW = 2999; // 0xbb7
field public static final int LAYOUT_CHANGED = 1; // 0x1
- field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1; // 0x1
field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0; // 0x0
field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2; // 0x2
+ field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1; // 0x1
field public static final int MEMORY_TYPE_CHANGED = 256; // 0x100
field public static final deprecated int MEMORY_TYPE_GPU = 2; // 0x2
field public static final deprecated int MEMORY_TYPE_HARDWARE = 1; // 0x1
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index bb16afddcd6..b6adee9501a 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -18,10 +18,6 @@ package android.view;
import static android.view.DisplayCutoutProto.BOUNDS;
import static android.view.DisplayCutoutProto.INSETS;
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
-import static android.view.Surface.ROTATION_270;
-import static android.view.Surface.ROTATION_90;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
@@ -36,23 +32,24 @@ import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import android.util.PathParser;
-import android.util.Size;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import java.util.Objects;
+import java.util.ArrayList;
+import java.util.List;
/**
- * Represents a part of the display that is not functional for displaying content.
+ * Represents the area of the display that is not functional for displaying content.
*
*
{@code DisplayCutout} is immutable.
*/
public final class DisplayCutout {
private static final String TAG = "DisplayCutout";
+ private static final String BOTTOM_MARKER = "@bottom";
private static final String DP_MARKER = "@dp";
/**
@@ -74,7 +71,7 @@ public final class DisplayCutout {
* @hide
*/
public static final DisplayCutout NO_CUTOUT = new DisplayCutout(ZERO_RECT, EMPTY_REGION,
- new Size(0, 0));
+ false /* copyArguments */);
private static final Object CACHE_LOCK = new Object();
@@ -89,38 +86,38 @@ public final class DisplayCutout {
private final Rect mSafeInsets;
private final Region mBounds;
- private final Size mFrameSize; // TODO: move frameSize, calculateRelativeTo, etc. into WM.
/**
* Creates a DisplayCutout instance.
*
* @param safeInsets the insets from each edge which avoid the display cutout as returned by
* {@link #getSafeInsetTop()} etc.
- * @param bounds the bounds of the display cutout as returned by {@link #getBounds()}.
+ * @param boundingRects the bounding rects of the display cutouts as returned by
+ * {@link #getBoundingRects()} ()}.
*/
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
- public DisplayCutout(Rect safeInsets, Region bounds) {
+ public DisplayCutout(Rect safeInsets, List boundingRects) {
this(safeInsets != null ? new Rect(safeInsets) : ZERO_RECT,
- bounds != null ? Region.obtain(bounds) : Region.obtain(),
- null /* frameSize */);
+ boundingRectsToRegion(boundingRects),
+ true /* copyArguments */);
}
/**
* Creates a DisplayCutout instance.
*
- * NOTE: the Rects passed into this instance are not copied and MUST remain unchanged.
- *
- * @hide
+ * @param copyArguments if true, create a copy of the arguments. If false, the passed arguments
+ * are not copied and MUST remain unchanged forever.
*/
- @VisibleForTesting
- public DisplayCutout(Rect safeInsets, Region bounds, Size frameSize) {
- mSafeInsets = safeInsets != null ? safeInsets : ZERO_RECT;
- mBounds = bounds != null ? bounds : Region.obtain();
- mFrameSize = frameSize;
+ private DisplayCutout(Rect safeInsets, Region bounds, boolean copyArguments) {
+ mSafeInsets = safeInsets == null ? ZERO_RECT :
+ (copyArguments ? new Rect(safeInsets) : safeInsets);
+ mBounds = bounds == null ? Region.obtain() :
+ (copyArguments ? Region.obtain(bounds) : bounds);
}
/**
- * Returns true if there is no cutout or it is outside of the content view.
+ * Returns true if the safe insets are empty (and therefore the current view does not
+ * overlap with the cutout or cutout area).
*
* @hide
*/
@@ -128,6 +125,15 @@ public final class DisplayCutout {
return mSafeInsets.equals(ZERO_RECT);
}
+ /**
+ * Returns true if there is no cutout, i.e. the bounds are empty.
+ *
+ * @hide
+ */
+ public boolean isBoundsEmpty() {
+ return mBounds.isEmpty();
+ }
+
/** Returns the inset from the top which avoids the display cutout in pixels. */
public int getSafeInsetTop() {
return mSafeInsets.top;
@@ -161,23 +167,60 @@ public final class DisplayCutout {
/**
* Returns the bounding region of the cutout.
*
+ *
+ * Note: There may be more than one cutout, in which case the returned
+ * {@code Region} will be non-contiguous and its bounding rect will be meaningless without
+ * intersecting it first.
+ *
+ * Example:
+ *
+ * // Getting the bounding rectangle of the top display cutout
+ * Region bounds = displayCutout.getBounds();
+ * bounds.op(0, 0, Integer.MAX_VALUE, displayCutout.getSafeInsetTop(), Region.Op.INTERSECT);
+ * Rect topDisplayCutout = bounds.getBoundingRect();
+ *
+ *
* @return the bounding region of the cutout. Coordinates are relative
* to the top-left corner of the content view and in pixel units.
+ * @hide
*/
public Region getBounds() {
return Region.obtain(mBounds);
}
/**
- * Returns the bounding rect of the cutout.
+ * Returns a list of {@code Rect}s, each of which is the bounding rectangle for a non-functional
+ * area on the display.
*
- * @return the bounding rect of the cutout. Coordinates are relative
- * to the top-left corner of the content view.
- * @hide
+ * There will be at most one non-functional area per short edge of the device, and none on
+ * the long edges.
+ *
+ * @return a list of bounding {@code Rect}s, one for each display cutout area.
*/
- public Rect getBoundingRect() {
- // TODO(roosa): Inline.
- return mBounds.getBounds();
+ public List getBoundingRects() {
+ List result = new ArrayList<>();
+ Region bounds = Region.obtain();
+ // top
+ bounds.set(mBounds);
+ bounds.op(0, 0, Integer.MAX_VALUE, getSafeInsetTop(), Region.Op.INTERSECT);
+ if (!bounds.isEmpty()) {
+ result.add(bounds.getBounds());
+ }
+ // left
+ bounds.set(mBounds);
+ bounds.op(0, 0, getSafeInsetLeft(), Integer.MAX_VALUE, Region.Op.INTERSECT);
+ if (!bounds.isEmpty()) {
+ result.add(bounds.getBounds());
+ }
+ // right & bottom
+ bounds.set(mBounds);
+ bounds.op(getSafeInsetLeft() + 1, getSafeInsetTop() + 1,
+ Integer.MAX_VALUE, Integer.MAX_VALUE, Region.Op.INTERSECT);
+ if (!bounds.isEmpty()) {
+ result.add(bounds.getBounds());
+ }
+ bounds.recycle();
+ return result;
}
@Override
@@ -195,8 +238,7 @@ public final class DisplayCutout {
if (o instanceof DisplayCutout) {
DisplayCutout c = (DisplayCutout) o;
return mSafeInsets.equals(c.mSafeInsets)
- && mBounds.equals(c.mBounds)
- && Objects.equals(mFrameSize, c.mFrameSize);
+ && mBounds.equals(c.mBounds);
}
return false;
}
@@ -204,7 +246,7 @@ public final class DisplayCutout {
@Override
public String toString() {
return "DisplayCutout{insets=" + mSafeInsets
- + " boundingRect=" + getBoundingRect()
+ + " boundingRect=" + mBounds.getBounds()
+ "}";
}
@@ -249,88 +291,19 @@ public final class DisplayCutout {
}
bounds.translate(-insetLeft, -insetTop);
- Size frame = mFrameSize == null ? null : new Size(
- mFrameSize.getWidth() - insetLeft - insetRight,
- mFrameSize.getHeight() - insetTop - insetBottom);
-
- return new DisplayCutout(safeInsets, bounds, frame);
+ return new DisplayCutout(safeInsets, bounds, false /* copyArguments */);
}
/**
- * Recalculates the cutout relative to the given reference frame.
- *
- * The safe insets must already have been computed, e.g. with {@link #computeSafeInsets}.
+ * Returns a copy of this instance with the safe insets replaced with the parameter.
*
- * @return a copy of this instance with the safe insets recalculated
- * @hide
- */
- public DisplayCutout calculateRelativeTo(Rect frame) {
- return inset(frame.left, frame.top,
- mFrameSize.getWidth() - frame.right, mFrameSize.getHeight() - frame.bottom);
- }
-
- /**
- * Calculates the safe insets relative to the given display size.
+ * @param safeInsets the new safe insets in pixels
+ * @return a copy of this instance with the safe insets replaced with the argument.
*
- * @return a copy of this instance with the safe insets calculated
* @hide
*/
- public DisplayCutout computeSafeInsets(int width, int height) {
- if (this == NO_CUTOUT || mBounds.isEmpty()) {
- return NO_CUTOUT;
- }
-
- return computeSafeInsets(new Size(width, height), mBounds);
- }
-
- private static DisplayCutout computeSafeInsets(Size displaySize, Region bounds) {
- Rect boundingRect = bounds.getBounds();
- Rect safeRect = new Rect();
-
- int bestArea = 0;
- int bestVariant = 0;
- for (int variant = ROTATION_0; variant <= ROTATION_270; variant++) {
- int area = calculateInsetVariantArea(displaySize, boundingRect, variant, safeRect);
- if (bestArea < area) {
- bestArea = area;
- bestVariant = variant;
- }
- }
- calculateInsetVariantArea(displaySize, boundingRect, bestVariant, safeRect);
- if (safeRect.isEmpty()) {
- // The entire displaySize overlaps with the cutout.
- safeRect.set(0, displaySize.getHeight(), 0, 0);
- } else {
- // Convert safeRect to insets relative to displaySize. We're reusing the rect here to
- // avoid an allocation.
- safeRect.set(
- Math.max(0, safeRect.left),
- Math.max(0, safeRect.top),
- Math.max(0, displaySize.getWidth() - safeRect.right),
- Math.max(0, displaySize.getHeight() - safeRect.bottom));
- }
-
- return new DisplayCutout(safeRect, bounds, displaySize);
- }
-
- private static int calculateInsetVariantArea(Size display, Rect boundingRect, int variant,
- Rect outSafeRect) {
- switch (variant) {
- case ROTATION_0:
- outSafeRect.set(0, 0, display.getWidth(), boundingRect.top);
- break;
- case ROTATION_90:
- outSafeRect.set(0, 0, boundingRect.left, display.getHeight());
- break;
- case ROTATION_180:
- outSafeRect.set(0, boundingRect.bottom, display.getWidth(), display.getHeight());
- break;
- case ROTATION_270:
- outSafeRect.set(boundingRect.right, 0, display.getWidth(), display.getHeight());
- break;
- }
-
- return outSafeRect.isEmpty() ? 0 : outSafeRect.width() * outSafeRect.height();
+ public DisplayCutout replaceSafeInsets(Rect safeInsets) {
+ return new DisplayCutout(new Rect(safeInsets), mBounds, false /* copyArguments */);
}
private static int atLeastZero(int value) {
@@ -369,7 +342,7 @@ public final class DisplayCutout {
Region bounds = new Region();
bounds.setPath(path, clipRegion);
clipRegion.recycle();
- return new DisplayCutout(ZERO_RECT, bounds, null /* frameSize */);
+ return new DisplayCutout(ZERO_RECT, bounds, false /* copyArguments */);
}
/**
@@ -377,9 +350,9 @@ public final class DisplayCutout {
*
* @hide
*/
- public static DisplayCutout fromResources(Resources res, int displayWidth) {
+ public static DisplayCutout fromResources(Resources res, int displayWidth, int displayHeight) {
return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
- displayWidth, res.getDisplayMetrics().density);
+ displayWidth, displayHeight, res.getDisplayMetrics().density);
}
/**
@@ -388,7 +361,8 @@ public final class DisplayCutout {
* @hide
*/
@VisibleForTesting(visibility = PRIVATE)
- public static DisplayCutout fromSpec(String spec, int displayWidth, float density) {
+ public static DisplayCutout fromSpec(String spec, int displayWidth, int displayHeight,
+ float density) {
if (TextUtils.isEmpty(spec)) {
return null;
}
@@ -404,7 +378,14 @@ public final class DisplayCutout {
spec = spec.substring(0, spec.length() - DP_MARKER.length());
}
- Path p;
+ String bottomSpec = null;
+ if (spec.contains(BOTTOM_MARKER)) {
+ String[] splits = spec.split(BOTTOM_MARKER, 2);
+ spec = splits[0].trim();
+ bottomSpec = splits[1].trim();
+ }
+
+ final Path p;
try {
p = PathParser.createPathFromPathData(spec);
} catch (Throwable e) {
@@ -419,6 +400,20 @@ public final class DisplayCutout {
m.postTranslate(displayWidth / 2f, 0);
p.transform(m);
+ if (bottomSpec != null) {
+ final Path bottomPath;
+ try {
+ bottomPath = PathParser.createPathFromPathData(bottomSpec);
+ } catch (Throwable e) {
+ Log.wtf(TAG, "Could not inflate bottom cutout: ", e);
+ return null;
+ }
+ // Keep top transform
+ m.postTranslate(0, displayHeight);
+ bottomPath.transform(m);
+ p.addPath(bottomPath);
+ }
+
final DisplayCutout result = fromBounds(p);
synchronized (CACHE_LOCK) {
sCachedSpec = spec;
@@ -429,6 +424,16 @@ public final class DisplayCutout {
return result;
}
+ private static Region boundingRectsToRegion(List rects) {
+ Region result = Region.obtain();
+ if (rects != null) {
+ for (Rect r : rects) {
+ result.op(r, Region.Op.UNION);
+ }
+ }
+ return result;
+ }
+
/**
* Helper class for passing {@link DisplayCutout} through binder.
*
@@ -472,12 +477,6 @@ public final class DisplayCutout {
out.writeInt(1);
out.writeTypedObject(cutout.mSafeInsets, flags);
out.writeTypedObject(cutout.mBounds, flags);
- if (cutout.mFrameSize != null) {
- out.writeInt(cutout.mFrameSize.getWidth());
- out.writeInt(cutout.mFrameSize.getHeight());
- } else {
- out.writeInt(-1);
- }
}
}
@@ -520,10 +519,7 @@ public final class DisplayCutout {
Rect safeInsets = in.readTypedObject(Rect.CREATOR);
Region bounds = in.readTypedObject(Region.CREATOR);
- int width = in.readInt();
- Size frameSize = width >= 0 ? new Size(width, in.readInt()) : null;
-
- return new DisplayCutout(safeInsets, bounds, frameSize);
+ return new DisplayCutout(safeInsets, bounds, false /* copyArguments */);
}
public DisplayCutout get() {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 2354f255c30..69938cbe8bb 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2241,18 +2241,20 @@ public interface WindowManager extends ViewManager {
/**
* The window is allowed to extend into the {@link DisplayCutout} area, only if the
- * {@link DisplayCutout} is fully contained within the status bar. Otherwise, the window is
+ * {@link DisplayCutout} is fully contained within a system bar. Otherwise, the window is
* laid out such that it does not overlap with the {@link DisplayCutout} area.
*
*
* In practice, this means that if the window did not set FLAG_FULLSCREEN or
- * SYSTEM_UI_FLAG_FULLSCREEN, it can extend into the cutout area in portrait.
- * Otherwise (i.e. fullscreen or landscape) it is laid out such that it does overlap the
+ * SYSTEM_UI_FLAG_FULLSCREEN, it can extend into the cutout area in portrait if the cutout
+ * is at the top edge. Similarly for SYSTEM_UI_FLAG_HIDE_NAVIGATION and a cutout at the
+ * bottom of the screen.
+ * Otherwise (i.e. fullscreen or landscape) it is laid out such that it does not overlap the
* cutout area.
*
*
- * The usual precautions for not overlapping with the status bar are sufficient for ensuring
- * that no important content overlaps with the DisplayCutout.
+ * The usual precautions for not overlapping with the status and navigation bar are
+ * sufficient for ensuring that no important content overlaps with the DisplayCutout.
*
* @see DisplayCutout
* @see WindowInsets
@@ -2260,8 +2262,18 @@ public interface WindowManager extends ViewManager {
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT = 0;
/**
- * The window is always allowed to extend into the {@link DisplayCutout} area,
- * even if fullscreen or in landscape.
+ * @deprecated use {@link #LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES}
+ * @hide
+ */
+ @Deprecated
+ public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1;
+
+ /**
+ * The window is always allowed to extend into the {@link DisplayCutout} areas on the short
+ * edges of the screen.
+ *
+ * The window will never extend into a {@link DisplayCutout} area on the long edges of the
+ * screen.
*
*
* The window must make sure that no important content overlaps with the
@@ -2270,7 +2282,7 @@ public interface WindowManager extends ViewManager {
* @see DisplayCutout
* @see WindowInsets#getDisplayCutout()
*/
- public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 1;
+ public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1;
/**
* The window is never allowed to overlap with the DisplayCutout area.
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 021e88ea609..b81a74d8975 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2125,29 +2125,32 @@
Defaults to {@code default}.
@see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
- @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
@see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
@see android.view.DisplayCutout
@see android.R.attr#layoutInDisplayCutoutMode -->
-
-
+
" + keySetResult);
+ Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId + " response: " + response
+ + " --> " + keySetResult);
return keySetResult;
@@ -3570,23 +3715,29 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
public void restoreDrmKeys(@NonNull byte[] keySetId)
throws NoDrmSchemeException
{
- Log.v(TAG, "restoreDrmKeys: keySetId: " + keySetId);
+ addTask(new Task(CALL_COMPLETED_RESTORE_DRM_KEYS, false) {
+ @Override
+ void process() throws NoDrmSchemeException {
+ Log.v(TAG, "restoreDrmKeys: keySetId: " + keySetId);
- synchronized (mDrmLock) {
+ synchronized (mDrmLock) {
- if (!mActiveDrmScheme) {
- Log.w(TAG, "restoreDrmKeys NoDrmSchemeException");
- throw new NoDrmSchemeExceptionImpl("restoreDrmKeys: Has to set a DRM scheme first.");
- }
+ if (!mActiveDrmScheme) {
+ Log.w(TAG, "restoreDrmKeys NoDrmSchemeException");
+ throw new NoDrmSchemeExceptionImpl(
+ "restoreDrmKeys: Has to set a DRM scheme first.");
+ }
- try {
- mDrmObj.restoreKeys(mDrmSessionId, keySetId);
- } catch (Exception e) {
- Log.w(TAG, "restoreKeys Exception " + e);
- throw e;
- }
+ try {
+ mDrmObj.restoreKeys(mDrmSessionId, keySetId);
+ } catch (Exception e) {
+ Log.w(TAG, "restoreKeys Exception " + e);
+ throw e;
+ }
- } // synchronized
+ } // synchronized
+ }
+ });
}
@@ -3611,7 +3762,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
if (!mActiveDrmScheme && !mDrmConfigAllowed) {
Log.w(TAG, "getDrmPropertyString NoDrmSchemeException");
- throw new NoDrmSchemeExceptionImpl("getDrmPropertyString: Has to prepareDrm() first.");
+ throw new NoDrmSchemeExceptionImpl(
+ "getDrmPropertyString: Has to prepareDrm() first.");
}
try {
@@ -3649,7 +3801,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
if ( !mActiveDrmScheme && !mDrmConfigAllowed ) {
Log.w(TAG, "setDrmPropertyString NoDrmSchemeException");
- throw new NoDrmSchemeExceptionImpl("setDrmPropertyString: Has to prepareDrm() first.");
+ throw new NoDrmSchemeExceptionImpl(
+ "setDrmPropertyString: Has to prepareDrm() first.");
}
try {
@@ -4587,34 +4740,61 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private abstract class Task implements Runnable {
private final int mMediaCallType;
private final boolean mNeedToWaitForEventToComplete;
+ private DataSourceDesc mDSD;
public Task (int mediaCallType, boolean needToWaitForEventToComplete) {
mMediaCallType = mediaCallType;
mNeedToWaitForEventToComplete = needToWaitForEventToComplete;
}
- abstract int process();
+ abstract void process() throws IOException, NoDrmSchemeException;
@Override
public void run() {
- int status = process();
+ int status = CALL_STATUS_NO_ERROR;
+ try {
+ process();
+ } catch (IllegalStateException e) {
+ status = CALL_STATUS_INVALID_OPERATION;
+ } catch (IllegalArgumentException e) {
+ status = CALL_STATUS_BAD_VALUE;
+ } catch (SecurityException e) {
+ status = CALL_STATUS_PERMISSION_DENIED;
+ } catch (IOException e) {
+ status = CALL_STATUS_ERROR_IO;
+ } catch (NoDrmSchemeException e) {
+ status = CALL_STATUS_NO_DRM_SCHEME;
+ } catch (Exception e) {
+ status = CALL_STATUS_ERROR_UNKNOWN;
+ }
+ synchronized (mSrcLock) {
+ mDSD = mCurrentDSD;
+ }
+
+ // TODO: Make native implementations asynchronous and let them send notifications.
+ if (!mNeedToWaitForEventToComplete || status != CALL_STATUS_NO_ERROR) {
+
+ sendCompleteNotification(status);
- if (!mNeedToWaitForEventToComplete) {
- final DataSourceDesc dsd;
- synchronized (mSrcLock) {
- dsd = mCurrentDSD;
- }
- synchronized (mEventCbLock) {
- for (Pair cb : mEventCallbackRecords) {
- cb.first.execute(() -> cb.second.onCallComplete(
- MediaPlayer2Impl.this, dsd, mMediaCallType, status));
- }
- }
synchronized (mTaskLock) {
mCurrentTask = null;
processPendingTask_l();
}
}
}
+
+ private void sendCompleteNotification(int status) {
+ // In {@link #notifyWhenCommandLabelReached} case, a separate callback
+ // {#link #onCommandLabelReached} is already called in {@code process()}.
+ if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED) {
+ return;
+ }
+ synchronized (mEventCbLock) {
+ for (Pair cb : mEventCallbackRecords) {
+ cb.first.execute(() -> cb.second.onCallCompleted(
+ MediaPlayer2Impl.this, mDSD, mMediaCallType, status));
+ }
+ }
+ }
};
}
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 918b82b0657..918a375a6e8 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -1489,7 +1489,7 @@ static const JNINativeMethod gMethods[] = {
{"nativePlayNextDataSource", "(J)V", (void *)android_media_MediaPlayer2_playNextDataSource},
{"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer2_setVideoSurface},
{"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer2_getBufferingParams},
- {"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams},
+ {"_setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams},
{"_prepare", "()V", (void *)android_media_MediaPlayer2_prepare},
{"_start", "()V", (void *)android_media_MediaPlayer2_start},
{"_stop", "()V", (void *)android_media_MediaPlayer2_stop},
@@ -1497,9 +1497,9 @@ static const JNINativeMethod gMethods[] = {
{"getVideoWidth", "()I", (void *)android_media_MediaPlayer2_getVideoWidth},
{"getVideoHeight", "()I", (void *)android_media_MediaPlayer2_getVideoHeight},
{"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaPlayer2_native_getMetrics},
- {"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer2_setPlaybackParams},
+ {"_setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer2_setPlaybackParams},
{"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer2_getPlaybackParams},
- {"setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer2_setSyncParams},
+ {"_setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer2_setSyncParams},
{"getSyncParams", "()Landroid/media/SyncParams;", (void *)android_media_MediaPlayer2_getSyncParams},
{"_seekTo", "(JI)V", (void *)android_media_MediaPlayer2_seekTo},
{"_notifyAt", "(J)V", (void *)android_media_MediaPlayer2_notifyAt},
@@ -1522,9 +1522,9 @@ static const JNINativeMethod gMethods[] = {
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer2_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaPlayer2_native_finalize},
{"getAudioSessionId", "()I", (void *)android_media_MediaPlayer2_get_audio_session_id},
- {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer2_set_audio_session_id},
+ {"_setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer2_set_audio_session_id},
{"_setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer2_setAuxEffectSendLevel},
- {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer2_attachAuxEffect},
+ {"_attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer2_attachAuxEffect},
// Modular DRM
{ "_prepareDrm", "([B[B)V", (void *)android_media_MediaPlayer2_prepareDrm },
{ "_releaseDrm", "()V", (void *)android_media_MediaPlayer2_releaseDrm },
--
GitLab
From 308ed7266ca88faa67a2b3f205f65ae9b099bdb6 Mon Sep 17 00:00:00 2001
From: Sunny Goyal
Date: Mon, 12 Mar 2018 11:35:57 -0700
Subject: [PATCH 080/488] Passing the TaskDescription to the IconLoader
Bug: 74445840
Test: Verified corresponding launcher change
Change-Id: I82a7d595aa0c128b50a699d7ac2ba688dc3cec9f
---
.../shared/recents/model/IconLoader.java | 27 ++++++++++++-------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/IconLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/IconLoader.java
index 3bc1d9a0588..14767f1c63b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/IconLoader.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/IconLoader.java
@@ -103,12 +103,13 @@ public abstract class IconLoader {
int userId = taskKey.userId;
Bitmap tdIcon = desc.getInMemoryIcon();
if (tdIcon != null) {
- return createDrawableFromBitmap(tdIcon, userId);
+ return createDrawableFromBitmap(tdIcon, userId, desc);
}
if (desc.getIconResource() != 0) {
// TODO: Use task context here
try {
- return createBadgedDrawable(mContext.getDrawable(desc.getIconResource()), userId);
+ return createBadgedDrawable(
+ mContext.getDrawable(desc.getIconResource()), userId, desc);
} catch (Resources.NotFoundException e) {
Log.e(TAG, "Could not find icon drawable from resource", e);
}
@@ -117,13 +118,13 @@ public abstract class IconLoader {
tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon(
desc.getIconFilename(), userId);
if (tdIcon != null) {
- return createDrawableFromBitmap(tdIcon, userId);
+ return createDrawableFromBitmap(tdIcon, userId, desc);
}
// Load the icon from the activity info and cache it
ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
if (activityInfo != null) {
- Drawable icon = getBadgedActivityIcon(activityInfo, userId);
+ Drawable icon = getBadgedActivityIcon(activityInfo, userId, desc);
if (icon != null) {
return icon;
}
@@ -135,16 +136,20 @@ public abstract class IconLoader {
public abstract Drawable getDefaultIcon(int userId);
- protected Drawable createDrawableFromBitmap(Bitmap icon, int userId) {
- return createBadgedDrawable(new BitmapDrawable(mContext.getResources(), icon), userId);
+ protected Drawable createDrawableFromBitmap(Bitmap icon, int userId,
+ ActivityManager.TaskDescription desc) {
+ return createBadgedDrawable(
+ new BitmapDrawable(mContext.getResources(), icon), userId, desc);
}
- protected abstract Drawable createBadgedDrawable(Drawable icon, int userId);
+ protected abstract Drawable createBadgedDrawable(Drawable icon, int userId,
+ ActivityManager.TaskDescription desc);
/**
* @return the activity icon for the ActivityInfo for a user, badging if necessary.
*/
- protected abstract Drawable getBadgedActivityIcon(ActivityInfo info, int userId);
+ protected abstract Drawable getBadgedActivityIcon(ActivityInfo info, int userId,
+ ActivityManager.TaskDescription desc);
public static class DefaultIconLoader extends IconLoader {
@@ -168,7 +173,8 @@ public abstract class IconLoader {
}
@Override
- protected Drawable createBadgedDrawable(Drawable icon, int userId) {
+ protected Drawable createBadgedDrawable(Drawable icon, int userId,
+ ActivityManager.TaskDescription desc) {
if (userId != UserHandle.myUserId()) {
icon = mContext.getPackageManager().getUserBadgedIcon(icon, new UserHandle(userId));
}
@@ -176,7 +182,8 @@ public abstract class IconLoader {
}
@Override
- protected Drawable getBadgedActivityIcon(ActivityInfo info, int userId) {
+ protected Drawable getBadgedActivityIcon(ActivityInfo info, int userId,
+ ActivityManager.TaskDescription desc) {
return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId);
}
}
--
GitLab
From ad52f4b97c897689d0b4dbfe344229a9970136eb Mon Sep 17 00:00:00 2001
From: Abodunrinwa Toki
Date: Tue, 6 Feb 2018 23:32:41 +0000
Subject: [PATCH 081/488] TextClassifierService.onSelectionEvent
Bug: 74466564
Bug: 67609167
Test: bit FrameworksCoreTests:android.view.textclassifier.TextClassificationManagerTest
Test: bit FrameworksCoreTests:android.view.textclassifier.logging.SelectionEventTest
Merged-In: Ib5af1ec80a38432d1201fbc913acdc3597d6ba82
Change-Id: Ib5af1ec80a38432d1201fbc913acdc3597d6ba82
---
api/current.txt | 5 +-
api/system-current.txt | 1 +
.../ITextClassifierService.aidl | 5 +-
.../textclassifier/TextClassifierService.java | 16 +++
.../android/view/textclassifier/Logger.java | 5 +-
.../view/textclassifier/SelectionEvent.aidl | 19 +++
.../view/textclassifier/SelectionEvent.java | 128 ++++++++++++++++--
.../textclassifier/SystemTextClassifier.java | 32 +++++
.../view/textclassifier/TextClassifier.java | 1 +
.../textclassifier/TextClassifierImpl.java | 17 ++-
.../widget/SelectionActionModeHelper.java | 3 +
.../textclassifier/SelectionEventTest.java | 50 +++++++
.../TextClassificationManagerService.java | 71 +++++++---
13 files changed, 313 insertions(+), 40 deletions(-)
create mode 100644 core/java/android/view/textclassifier/SelectionEvent.aidl
create mode 100644 core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
diff --git a/api/current.txt b/api/current.txt
index 3193d3026ab..037dba9f881 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -51067,7 +51067,8 @@ package android.view.textclassifier {
method public java.lang.String getWidgetVersion();
}
- public final class SelectionEvent {
+ public final class SelectionEvent implements android.os.Parcelable {
+ method public int describeContents();
method public long getDurationSincePreviousEvent();
method public long getDurationSinceSessionStart();
method public int getEnd();
@@ -51084,6 +51085,7 @@ package android.view.textclassifier {
method public int getStart();
method public java.lang.String getWidgetType();
method public java.lang.String getWidgetVersion();
+ method public void writeToParcel(android.os.Parcel, int);
field public static final int ACTION_ABANDON = 107; // 0x6b
field public static final int ACTION_COPY = 101; // 0x65
field public static final int ACTION_CUT = 103; // 0x67
@@ -51095,6 +51097,7 @@ package android.view.textclassifier {
field public static final int ACTION_SELECT_ALL = 200; // 0xc8
field public static final int ACTION_SHARE = 104; // 0x68
field public static final int ACTION_SMART_SHARE = 105; // 0x69
+ field public static final android.os.Parcelable.Creator CREATOR;
field public static final int EVENT_AUTO_SELECTION = 5; // 0x5
field public static final int EVENT_SELECTION_MODIFIED = 2; // 0x2
field public static final int EVENT_SELECTION_STARTED = 1; // 0x1
diff --git a/api/system-current.txt b/api/system-current.txt
index c80f239bdb7..e2053313a0e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4707,6 +4707,7 @@ package android.service.textclassifier {
method public final android.os.IBinder onBind(android.content.Intent);
method public abstract void onClassifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback);
method public abstract void onGenerateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback);
+ method public void onSelectionEvent(android.view.textclassifier.SelectionEvent);
method public abstract void onSuggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.textclassifier.TextClassifierService";
}
diff --git a/core/java/android/service/textclassifier/ITextClassifierService.aidl b/core/java/android/service/textclassifier/ITextClassifierService.aidl
index d2ffe345ae3..25e9d454efb 100644
--- a/core/java/android/service/textclassifier/ITextClassifierService.aidl
+++ b/core/java/android/service/textclassifier/ITextClassifierService.aidl
@@ -19,13 +19,14 @@ package android.service.textclassifier;
import android.service.textclassifier.ITextClassificationCallback;
import android.service.textclassifier.ITextLinksCallback;
import android.service.textclassifier.ITextSelectionCallback;
+import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextLinks;
import android.view.textclassifier.TextSelection;
/**
* TextClassifierService binder interface.
- * See TextClassifier for interface documentation.
+ * See TextClassifier (and TextClassifier.Logger) for interface documentation.
* {@hide}
*/
oneway interface ITextClassifierService {
@@ -44,4 +45,6 @@ oneway interface ITextClassifierService {
in CharSequence text,
in TextLinks.Options options,
in ITextLinksCallback c);
+
+ void onSelectionEvent(in SelectionEvent event);
}
diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java
index 57c8defe0d2..88e29b0d3d1 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -33,6 +33,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Slog;
+import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
@@ -171,6 +172,12 @@ public abstract class TextClassifierService extends Service {
}
});
}
+
+ /** {@inheritDoc} */
+ @Override
+ public void onSelectionEvent(SelectionEvent event) throws RemoteException {
+ TextClassifierService.this.onSelectionEvent(event);
+ }
};
@Nullable
@@ -237,6 +244,15 @@ public abstract class TextClassifierService extends Service {
@NonNull CancellationSignal cancellationSignal,
@NonNull Callback callback);
+ /**
+ * Writes the selection event.
+ * This is called when a selection event occurs. e.g. user changed selection; or smart selection
+ * happened.
+ *
+ *
+
+
+
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
new file mode 100644
index 00000000000..4628aa9e0f1
--- /dev/null
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.activity;
+
+import android.app.Activity;
+import android.app.IApplicationThread;
+import android.app.servertransaction.ActivityRelaunchItem;
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.ClientTransactionItem;
+import android.app.servertransaction.ResumeActivityItem;
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.MergedConfiguration;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for verifying {@link android.app.ActivityThread} class.
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class ActivityThreadTest {
+
+ private final ActivityTestRule mActivityTestRule =
+ new ActivityTestRule(TestActivity.class, true /* initialTouchMode */,
+ false /* launchActivity */);
+
+ @Test
+ public void testDoubleRelaunch() throws Exception {
+ final Activity activity = mActivityTestRule.launchActivity(new Intent());
+ final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
+
+ appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
+ appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ @Test
+ public void testResumeAfterRelaunch() throws Exception {
+ final Activity activity = mActivityTestRule.launchActivity(new Intent());
+ final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
+
+ appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
+ appThread.scheduleTransaction(newResumeTransaction(activity));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
+ final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
+ null, 0, new MergedConfiguration(),
+ false /* preserveWindow */);
+ final ResumeActivityItem resumeStateRequest =
+ ResumeActivityItem.obtain(true /* isForward */);
+ final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
+ final ClientTransaction transaction =
+ ClientTransaction.obtain(appThread, activity.getActivityToken());
+ transaction.addCallback(callbackItem);
+ transaction.setLifecycleStateRequest(resumeStateRequest);
+
+ return transaction;
+ }
+
+ private static ClientTransaction newResumeTransaction(Activity activity) {
+ final ResumeActivityItem resumeStateRequest =
+ ResumeActivityItem.obtain(true /* isForward */);
+ final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
+ final ClientTransaction transaction =
+ ClientTransaction.obtain(appThread, activity.getActivityToken());
+ transaction.setLifecycleStateRequest(resumeStateRequest);
+
+ return transaction;
+ }
+
+ // Test activity
+ public static class TestActivity extends Activity {
+ }
+}
--
GitLab
From db18cdae661b87ff2de3847947906da735f8d5eb Mon Sep 17 00:00:00 2001
From: yinxu
Date: Mon, 12 Mar 2018 14:07:49 -0700
Subject: [PATCH 088/488] Fix a bug when calling onError(int)
The lambda expression is executed on executor, so it is possible that
the message has been updated. The correct way is to fetch the
message.arg1 and use that value in the lamda expression.
Bug:73750871
Test: Unit Test
Change-Id: Id13f5fabf7eaad6970ab66a83a17aba7f1eebfce
---
telephony/java/android/telephony/TelephonyScanManager.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 946cecfa261..99e2db883e5 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -145,7 +145,8 @@ public final class TelephonyScanManager {
break;
case CALLBACK_SCAN_ERROR:
try {
- executor.execute(() -> callback.onError(message.arg1));
+ final int errorCode = message.arg1;
+ executor.execute(() -> callback.onError(errorCode));
} catch (Exception e) {
Rlog.e(TAG, "Exception in networkscan callback onError", e);
}
--
GitLab
From 66cffd5ae6546fb1e586565ed96e5af58ccf46c4 Mon Sep 17 00:00:00 2001
From: Jason Monk
Date: Mon, 12 Mar 2018 16:42:48 -0400
Subject: [PATCH 089/488] Run slice callbacks on thread they come in on
Instead post a runnable that will trigger an ANR+crash if the app
doesn't respond in time.
Test: atest cts/tests/tests/slice
Bug: 74251457
Change-Id: Ieea7a8d8cb08d3bf0735b9f7b385f286839dacd8
---
api/current.txt | 1 -
.../java/android/app/slice/SliceProvider.java | 105 ++++++------------
2 files changed, 32 insertions(+), 74 deletions(-)
diff --git a/api/current.txt b/api/current.txt
index 7e30e857eec..02654a4dbc7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7276,7 +7276,6 @@ package android.app.slice {
public abstract class SliceProvider extends android.content.ContentProvider {
ctor public SliceProvider();
method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
- method public final java.lang.String getBindingPackage();
method public final java.lang.String getType(android.net.Uri);
method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
method public android.app.slice.Slice onBindSlice(android.net.Uri, java.util.List);
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index 64a5181668b..fd417d6d80e 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -16,7 +16,6 @@
package android.app.slice;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.ContentProvider;
@@ -35,7 +34,6 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
-import android.os.Looper;
import android.os.Process;
import android.os.StrictMode;
import android.os.StrictMode.ThreadPolicy;
@@ -46,7 +44,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
/**
* A SliceProvider allows an app to provide content to be displayed in system spaces. This content
@@ -162,18 +159,10 @@ public abstract class SliceProvider extends ContentProvider {
private static final boolean DEBUG = false;
- private String mBindingPkg;
- private SliceManager mSliceManager;
+ private static final long SLICE_BIND_ANR = 2000;
- /**
- * Return the package name of the caller that initiated the binding request
- * currently happening. The returned package will have been
- * verified to belong to the calling UID. Returns {@code null} if not
- * currently performing an {@link #onBindSlice(Uri, List)}.
- */
- public final @Nullable String getBindingPackage() {
- return mBindingPkg;
- }
+ private String mCallback;
+ private SliceManager mSliceManager;
@Override
public void attachInfo(Context context, ProviderInfo info) {
@@ -182,12 +171,12 @@ public abstract class SliceProvider extends ContentProvider {
}
/**
- * Implemented to create a slice. Will be called on the main thread.
+ * Implemented to create a slice.
*
* onBindSlice should return as quickly as possible so that the UI tied
* to this slice can be responsive. No network or other IO will be allowed
* during onBindSlice. Any loading that needs to be done should happen
- * off the main thread with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)}
+ * in the background with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)}
* when the app is ready to provide the complete data in onBindSlice.
*
* The slice returned should have a spec that is compatible with one of
@@ -375,55 +364,32 @@ public abstract class SliceProvider extends ContentProvider {
}
private Collection handleGetDescendants(Uri uri) {
- if (Looper.myLooper() == Looper.getMainLooper()) {
+ mCallback = "onGetSliceDescendants";
+ Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
+ try {
return onGetSliceDescendants(uri);
- } else {
- CountDownLatch latch = new CountDownLatch(1);
- Collection[] output = new Collection[1];
- Handler.getMain().post(() -> {
- output[0] = onGetSliceDescendants(uri);
- latch.countDown();
- });
- try {
- latch.await();
- return output[0];
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
+ } finally {
+ Handler.getMain().removeCallbacks(mAnr);
}
}
private void handlePinSlice(Uri sliceUri) {
- if (Looper.myLooper() == Looper.getMainLooper()) {
+ mCallback = "onSlicePinned";
+ Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
+ try {
onSlicePinned(sliceUri);
- } else {
- CountDownLatch latch = new CountDownLatch(1);
- Handler.getMain().post(() -> {
- onSlicePinned(sliceUri);
- latch.countDown();
- });
- try {
- latch.await();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
+ } finally {
+ Handler.getMain().removeCallbacks(mAnr);
}
}
private void handleUnpinSlice(Uri sliceUri) {
- if (Looper.myLooper() == Looper.getMainLooper()) {
+ mCallback = "onSliceUnpinned";
+ Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
+ try {
onSliceUnpinned(sliceUri);
- } else {
- CountDownLatch latch = new CountDownLatch(1);
- Handler.getMain().post(() -> {
- onSliceUnpinned(sliceUri);
- latch.countDown();
- });
- try {
- latch.await();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
+ } finally {
+ Handler.getMain().removeCallbacks(mAnr);
}
}
@@ -441,21 +407,12 @@ public abstract class SliceProvider extends ContentProvider {
return createPermissionSlice(getContext(), sliceUri, pkg);
}
}
- if (Looper.myLooper() == Looper.getMainLooper()) {
- return onBindSliceStrict(sliceUri, supportedSpecs, pkg);
- } else {
- CountDownLatch latch = new CountDownLatch(1);
- Slice[] output = new Slice[1];
- Handler.getMain().post(() -> {
- output[0] = onBindSliceStrict(sliceUri, supportedSpecs, pkg);
- latch.countDown();
- });
- try {
- latch.await();
- return output[0];
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
+ mCallback = "onBindSlice";
+ Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
+ try {
+ return onBindSliceStrict(sliceUri, supportedSpecs);
+ } finally {
+ Handler.getMain().removeCallbacks(mAnr);
}
}
@@ -507,19 +464,21 @@ public abstract class SliceProvider extends ContentProvider {
}
}
- private Slice onBindSliceStrict(Uri sliceUri, List supportedSpecs,
- String callingPackage) {
+ private Slice onBindSliceStrict(Uri sliceUri, List supportedSpecs) {
ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
try {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyDeath()
.build());
- mBindingPkg = callingPackage;
return onBindSlice(sliceUri, supportedSpecs);
} finally {
- mBindingPkg = null;
StrictMode.setThreadPolicy(oldPolicy);
}
}
+
+ private final Runnable mAnr = () -> {
+ Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT);
+ Log.wtf(TAG, "Timed out while handling slice callback " + mCallback);
+ };
}
--
GitLab
From a89f6e1bb2076518068084fea53c4ee5c1306b4c Mon Sep 17 00:00:00 2001
From: Chong Zhang
Date: Wed, 7 Mar 2018 16:22:18 -0800
Subject: [PATCH 090/488] heif: add option for specifying bitmap pixel format
Add an option similar to BitmapFactory.Options to the bitmap
extraction APIs added in P to allow the app to specify bitmap's
pixel format. MediaMetadataRetriever's old getFrameAtTime()
only allows extraction in RGB565, for image use case the bitdepth
could be too low.
Also change return type of getFramesAtIndex to List as
Lint is complaining about returning raw arrays.
bug: 63633199
bug: 73886998
Change-Id: I40f0a421c767483e32c7744180dc5a187681e066
---
api/current.txt | 15 +-
.../android/media/MediaMetadataRetriever.java | 114 ++++++++--
.../android_media_MediaMetadataRetriever.cpp | 205 ++++++++++++++----
3 files changed, 265 insertions(+), 69 deletions(-)
diff --git a/api/current.txt b/api/current.txt
index fff502a577d..b7a869ef317 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -24015,13 +24015,13 @@ package android.media {
ctor public MediaMetadataRetriever();
method public java.lang.String extractMetadata(int);
method public byte[] getEmbeddedPicture();
- method public android.graphics.Bitmap getFrameAtIndex(int);
+ method public android.graphics.Bitmap getFrameAtIndex(int, android.media.MediaMetadataRetriever.BitmapParams);
method public android.graphics.Bitmap getFrameAtTime(long, int);
method public android.graphics.Bitmap getFrameAtTime(long);
method public android.graphics.Bitmap getFrameAtTime();
- method public android.graphics.Bitmap[] getFramesAtIndex(int, int);
- method public android.graphics.Bitmap getImageAtIndex(int);
- method public android.graphics.Bitmap getPrimaryImage();
+ method public java.util.List getFramesAtIndex(int, int, android.media.MediaMetadataRetriever.BitmapParams);
+ method public android.graphics.Bitmap getImageAtIndex(int, android.media.MediaMetadataRetriever.BitmapParams);
+ method public android.graphics.Bitmap getPrimaryImage(android.media.MediaMetadataRetriever.BitmapParams);
method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
method public void release();
method public void setDataSource(java.lang.String) throws java.lang.IllegalArgumentException;
@@ -24067,6 +24067,13 @@ package android.media {
field public static final int OPTION_PREVIOUS_SYNC = 0; // 0x0
}
+ public static final class MediaMetadataRetriever.BitmapParams {
+ ctor public MediaMetadataRetriever.BitmapParams();
+ method public android.graphics.Bitmap.Config getActualConfig();
+ method public android.graphics.Bitmap.Config getPreferredConfig();
+ method public void setPreferredConfig(android.graphics.Bitmap.Config);
+ }
+
public final class MediaMuxer {
ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException;
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 745eb74d6e2..1aeed6da3a3 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -17,6 +17,8 @@
package android.media;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
@@ -30,7 +32,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-
+import java.util.List;
import java.util.Map;
/**
@@ -367,27 +369,79 @@ public class MediaMetadataRetriever
private native Bitmap _getFrameAtTime(long timeUs, int option, int width, int height);
+ public static final class BitmapParams {
+ private Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
+ private Bitmap.Config outActualConfig = Bitmap.Config.ARGB_8888;
+
+ /**
+ * Create a default BitmapParams object. By default, it uses {@link Bitmap.Config#ARGB_8888}
+ * as the preferred bitmap config.
+ */
+ public BitmapParams() {}
+
+ /**
+ * Set the preferred bitmap config for the decoder to decode into.
+ *
+ * If not set, or the request cannot be met, the decoder will output
+ * in {@link Bitmap.Config#ARGB_8888} config by default.
+ *
+ * After decode, the actual config used can be retrieved by {@link #getActualConfig()}.
+ *
+ * @param config the preferred bitmap config to use.
+ */
+ public void setPreferredConfig(@NonNull Bitmap.Config config) {
+ if (config == null) {
+ throw new IllegalArgumentException("preferred config can't be null");
+ }
+ inPreferredConfig = config;
+ }
+
+ /**
+ * Retrieve the preferred bitmap config in the params.
+ *
+ * @return the preferred bitmap config.
+ */
+ public @NonNull Bitmap.Config getPreferredConfig() {
+ return inPreferredConfig;
+ }
+
+ /**
+ * Get the actual bitmap config used to decode the bitmap after the decoding.
+ *
+ * @return the actual bitmap config used.
+ */
+ public @NonNull Bitmap.Config getActualConfig() {
+ return outActualConfig;
+ }
+ }
+
/**
* This method retrieves a video frame by its index. It should only be called
* after {@link #setDataSource}.
*
+ * After the bitmap is returned, you can query the actual parameters that were
+ * used to create the bitmap from the {@code BitmapParams} argument, for instance
+ * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
+ *
* @param frameIndex 0-based index of the video frame. The frame index must be that of
* a valid frame. The total number of frames available for retrieval can be queried
* via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
+ * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
+ * If null, default config will be chosen.
*
* @throws IllegalStateException if the container doesn't contain video or image sequences.
* @throws IllegalArgumentException if the requested frame index does not exist.
*
* @return A Bitmap containing the requested video frame, or null if the retrieval fails.
*
- * @see #getFramesAtIndex(int, int)
+ * @see #getFramesAtIndex(int, int, BitmapParams)
*/
- public Bitmap getFrameAtIndex(int frameIndex) {
- Bitmap[] bitmaps = getFramesAtIndex(frameIndex, 1);
- if (bitmaps == null || bitmaps.length < 1) {
+ public Bitmap getFrameAtIndex(int frameIndex, @Nullable BitmapParams params) {
+ List bitmaps = getFramesAtIndex(frameIndex, 1, params);
+ if (bitmaps == null || bitmaps.size() < 1) {
return null;
}
- return bitmaps[0];
+ return bitmaps.get(0);
}
/**
@@ -395,24 +449,31 @@ public class MediaMetadataRetriever
* specified index. It should only be called after {@link #setDataSource}.
*
* If the caller intends to retrieve more than one consecutive video frames,
- * this method is preferred over {@link #getFrameAtIndex(int)} for efficiency.
+ * this method is preferred over {@link #getFrameAtIndex(int, BitmapParams)} for efficiency.
+ *
+ * After the bitmaps are returned, you can query the actual parameters that were
+ * used to create the bitmaps from the {@code BitmapParams} argument, for instance
+ * to query the bitmap config used for the bitmaps with {@link BitmapParams#getActualConfig}.
*
* @param frameIndex 0-based index of the first video frame to retrieve. The frame index
* must be that of a valid frame. The total number of frames available for retrieval
* can be queried via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
* @param numFrames number of consecutive video frames to retrieve. Must be a positive
* value. The stream must contain at least numFrames frames starting at frameIndex.
+ * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
+ * If null, default config will be chosen.
*
* @throws IllegalStateException if the container doesn't contain video or image sequences.
* @throws IllegalArgumentException if the frameIndex or numFrames is invalid, or the
* stream doesn't contain at least numFrames starting at frameIndex.
- * @return An array of Bitmaps containing the requested video frames. The returned
+ * @return An list of Bitmaps containing the requested video frames. The returned
* array could contain less frames than requested if the retrieval fails.
*
- * @see #getFrameAtIndex(int)
+ * @see #getFrameAtIndex(int, BitmapParams)
*/
- public Bitmap[] getFramesAtIndex(int frameIndex, int numFrames) {
+ public List getFramesAtIndex(
+ int frameIndex, int numFrames, @Nullable BitmapParams params) {
if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO))) {
throw new IllegalStateException("Does not contail video or image sequences");
}
@@ -424,24 +485,32 @@ public class MediaMetadataRetriever
throw new IllegalArgumentException("Invalid frameIndex or numFrames: "
+ frameIndex + ", " + numFrames);
}
- return _getFrameAtIndex(frameIndex, numFrames);
+ return _getFrameAtIndex(frameIndex, numFrames, params);
}
- private native Bitmap[] _getFrameAtIndex(int frameIndex, int numFrames);
+ private native List _getFrameAtIndex(
+ int frameIndex, int numFrames, @Nullable BitmapParams params);
/**
* This method retrieves a still image by its index. It should only be called
* after {@link #setDataSource}.
*
+ * After the bitmap is returned, you can query the actual parameters that were
+ * used to create the bitmap from the {@code BitmapParams} argument, for instance
+ * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
+ *
* @param imageIndex 0-based index of the image, with negative value indicating
* the primary image.
+ * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
+ * If null, default config will be chosen.
+ *
* @throws IllegalStateException if the container doesn't contain still images.
* @throws IllegalArgumentException if the requested image does not exist.
*
* @return the requested still image, or null if the image cannot be retrieved.
*
- * @see #getPrimaryImage
+ * @see #getPrimaryImage(BitmapParams)
*/
- public Bitmap getImageAtIndex(int imageIndex) {
+ public Bitmap getImageAtIndex(int imageIndex, @Nullable BitmapParams params) {
if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE))) {
throw new IllegalStateException("Does not contail still images");
}
@@ -451,24 +520,31 @@ public class MediaMetadataRetriever
throw new IllegalArgumentException("Invalid image index: " + imageCount);
}
- return _getImageAtIndex(imageIndex);
+ return _getImageAtIndex(imageIndex, params);
}
/**
* This method retrieves the primary image of the media content. It should only
* be called after {@link #setDataSource}.
*
+ * After the bitmap is returned, you can query the actual parameters that were
+ * used to create the bitmap from the {@code BitmapParams} argument, for instance
+ * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
+ *
+ * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
+ * If null, default config will be chosen.
+ *
* @return the primary image, or null if it cannot be retrieved.
*
* @throws IllegalStateException if the container doesn't contain still images.
*
- * @see #getImageAtIndex(int)
+ * @see #getImageAtIndex(int, BitmapParams)
*/
- public Bitmap getPrimaryImage() {
- return getImageAtIndex(-1);
+ public Bitmap getPrimaryImage(@Nullable BitmapParams params) {
+ return getImageAtIndex(-1, params);
}
- private native Bitmap _getImageAtIndex(int imageIndex);
+ private native Bitmap _getImageAtIndex(int imageIndex, @Nullable BitmapParams params);
/**
* Call this method after setDataSource(). This method finds the optional
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index ff854c51c43..3a6714279bb 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
#include "jni.h"
@@ -45,6 +46,12 @@ struct fields_t {
jmethodID createScaledBitmapMethod;
jclass configClazz; // Must be a global ref
jmethodID createConfigMethod;
+ jclass bitmapParamsClazz; // Must be a global ref
+ jfieldID inPreferredConfig;
+ jfieldID outActualConfig;
+ jclass arrayListClazz; // Must be a global ref
+ jmethodID arrayListInit;
+ jmethodID arrayListAdd;
};
static fields_t fields;
@@ -254,16 +261,18 @@ static void rotate(T *dst, const T *src, size_t width, size_t height, int angle)
}
static jobject getBitmapFromVideoFrame(
- JNIEnv *env, VideoFrame *videoFrame, jint dst_width, jint dst_height) {
+ JNIEnv *env, VideoFrame *videoFrame, jint dst_width, jint dst_height,
+ SkColorType outColorType) {
ALOGV("getBitmapFromVideoFrame: dimension = %dx%d and bytes = %d",
videoFrame->mDisplayWidth,
videoFrame->mDisplayHeight,
videoFrame->mSize);
- jobject config = env->CallStaticObjectMethod(
- fields.configClazz,
- fields.createConfigMethod,
- GraphicsJNI::colorTypeToLegacyBitmapConfig(kRGB_565_SkColorType));
+ ScopedLocalRef config(env,
+ env->CallStaticObjectMethod(
+ fields.configClazz,
+ fields.createConfigMethod,
+ GraphicsJNI::colorTypeToLegacyBitmapConfig(outColorType)));
uint32_t width, height, displayWidth, displayHeight;
bool swapWidthAndHeight = false;
@@ -285,7 +294,7 @@ static jobject getBitmapFromVideoFrame(
fields.createBitmapMethod,
width,
height,
- config);
+ config.get());
if (jBitmap == NULL) {
if (env->ExceptionCheck()) {
env->ExceptionClear();
@@ -297,11 +306,19 @@ static jobject getBitmapFromVideoFrame(
SkBitmap bitmap;
GraphicsJNI::getSkBitmap(env, jBitmap, &bitmap);
- rotate((uint16_t*)bitmap.getPixels(),
- (uint16_t*)((char*)videoFrame + sizeof(VideoFrame)),
- videoFrame->mWidth,
- videoFrame->mHeight,
- videoFrame->mRotationAngle);
+ if (outColorType == kRGB_565_SkColorType) {
+ rotate((uint16_t*)bitmap.getPixels(),
+ (uint16_t*)((char*)videoFrame + sizeof(VideoFrame)),
+ videoFrame->mWidth,
+ videoFrame->mHeight,
+ videoFrame->mRotationAngle);
+ } else {
+ rotate((uint32_t*)bitmap.getPixels(),
+ (uint32_t*)((char*)videoFrame + sizeof(VideoFrame)),
+ videoFrame->mWidth,
+ videoFrame->mHeight,
+ videoFrame->mRotationAngle);
+ }
if (dst_width <= 0 || dst_height <= 0) {
dst_width = displayWidth;
@@ -323,12 +340,46 @@ static jobject getBitmapFromVideoFrame(
dst_width,
dst_height,
true);
+
+ env->DeleteLocalRef(jBitmap);
return scaledBitmap;
}
return jBitmap;
}
+static int getColorFormat(JNIEnv *env, jobject options) {
+ if (options == NULL) {
+ return HAL_PIXEL_FORMAT_RGBA_8888;
+ }
+
+ ScopedLocalRef inConfig(env, env->GetObjectField(options, fields.inPreferredConfig));
+ SkColorType prefColorType = GraphicsJNI::getNativeBitmapColorType(env, inConfig.get());
+
+ if (prefColorType == kRGB_565_SkColorType) {
+ return HAL_PIXEL_FORMAT_RGB_565;
+ }
+ return HAL_PIXEL_FORMAT_RGBA_8888;
+}
+
+static SkColorType setOutColorType(JNIEnv *env, int colorFormat, jobject options) {
+ SkColorType outColorType = kN32_SkColorType;
+ if (colorFormat == HAL_PIXEL_FORMAT_RGB_565) {
+ outColorType = kRGB_565_SkColorType;
+ }
+
+ if (options != NULL) {
+ ScopedLocalRef config(env,
+ env->CallStaticObjectMethod(
+ fields.configClazz,
+ fields.createConfigMethod,
+ GraphicsJNI::colorTypeToLegacyBitmapConfig(outColorType)));
+
+ env->SetObjectField(options, fields.outActualConfig, config.get());
+ }
+ return outColorType;
+}
+
static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
JNIEnv *env, jobject thiz, jlong timeUs, jint option, jint dst_width, jint dst_height)
{
@@ -351,11 +402,11 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
return NULL;
}
- return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height);
+ return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, kRGB_565_SkColorType);
}
static jobject android_media_MediaMetadataRetriever_getImageAtIndex(
- JNIEnv *env, jobject thiz, jint index)
+ JNIEnv *env, jobject thiz, jint index, jobject params)
{
ALOGV("getImageAtIndex: index %d", index);
sp retriever = getRetriever(env, thiz);
@@ -364,9 +415,11 @@ static jobject android_media_MediaMetadataRetriever_getImageAtIndex(
return NULL;
}
+ int colorFormat = getColorFormat(env, params);
+
// Call native method to retrieve an image
VideoFrame *videoFrame = NULL;
- sp frameMemory = retriever->getImageAtIndex(index);
+ sp frameMemory = retriever->getImageAtIndex(index, colorFormat);
if (frameMemory != 0) { // cast the shared structure to a VideoFrame object
videoFrame = static_cast(frameMemory->pointer());
}
@@ -375,11 +428,13 @@ static jobject android_media_MediaMetadataRetriever_getImageAtIndex(
return NULL;
}
- return getBitmapFromVideoFrame(env, videoFrame, -1, -1);
+ SkColorType outColorType = setOutColorType(env, colorFormat, params);
+
+ return getBitmapFromVideoFrame(env, videoFrame, -1, -1, outColorType);
}
-static jobjectArray android_media_MediaMetadataRetriever_getFrameAtIndex(
- JNIEnv *env, jobject thiz, jint frameIndex, jint numFrames)
+static jobject android_media_MediaMetadataRetriever_getFrameAtIndex(
+ JNIEnv *env, jobject thiz, jint frameIndex, jint numFrames, jobject params)
{
ALOGV("getFrameAtIndex: frameIndex %d, numFrames %d", frameIndex, numFrames);
sp retriever = getRetriever(env, thiz);
@@ -389,31 +444,34 @@ static jobjectArray android_media_MediaMetadataRetriever_getFrameAtIndex(
return NULL;
}
+ int colorFormat = getColorFormat(env, params);
+
std::vector > frames;
- status_t err = retriever->getFrameAtIndex(&frames, frameIndex, numFrames);
+ status_t err = retriever->getFrameAtIndex(&frames, frameIndex, numFrames, colorFormat);
if (err != OK || frames.size() == 0) {
ALOGE("failed to get frames from retriever, err=%d, size=%zu",
err, frames.size());
return NULL;
}
-
- jobjectArray bitmapArrayObj = env->NewObjectArray(
- frames.size(), fields.bitmapClazz, NULL);
- if (bitmapArrayObj == NULL) {
- ALOGE("can't create bitmap array object");
+ jobject arrayList = env->NewObject(fields.arrayListClazz, fields.arrayListInit);
+ if (arrayList == NULL) {
+ ALOGE("can't create bitmap array list object");
return NULL;
}
+ SkColorType outColorType = setOutColorType(env, colorFormat, params);
+
for (size_t i = 0; i < frames.size(); i++) {
if (frames[i] == NULL || frames[i]->pointer() == NULL) {
ALOGE("video frame at index %zu is a NULL pointer", frameIndex + i);
continue;
}
VideoFrame *videoFrame = static_cast(frames[i]->pointer());
- jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1);
- env->SetObjectArrayElement(bitmapArrayObj, i, bitmapObj);
+ jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1, outColorType);
+ env->CallBooleanMethod(arrayList, fields.arrayListAdd, bitmapObj);
+ env->DeleteLocalRef(bitmapObj);
}
- return bitmapArrayObj;
+ return arrayList;
}
static jbyteArray android_media_MediaMetadataRetriever_getEmbeddedPicture(
@@ -488,21 +546,21 @@ static void android_media_MediaMetadataRetriever_native_finalize(JNIEnv *env, jo
// first time an instance of this class is used.
static void android_media_MediaMetadataRetriever_native_init(JNIEnv *env)
{
- jclass clazz = env->FindClass(kClassPathName);
- if (clazz == NULL) {
+ ScopedLocalRef clazz(env, env->FindClass(kClassPathName));
+ if (clazz.get() == NULL) {
return;
}
- fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
+ fields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
if (fields.context == NULL) {
return;
}
- jclass bitmapClazz = env->FindClass("android/graphics/Bitmap");
- if (bitmapClazz == NULL) {
+ clazz.reset(env->FindClass("android/graphics/Bitmap"));
+ if (clazz.get() == NULL) {
return;
}
- fields.bitmapClazz = (jclass) env->NewGlobalRef(bitmapClazz);
+ fields.bitmapClazz = (jclass) env->NewGlobalRef(clazz.get());
if (fields.bitmapClazz == NULL) {
return;
}
@@ -521,11 +579,11 @@ static void android_media_MediaMetadataRetriever_native_init(JNIEnv *env)
return;
}
- jclass configClazz = env->FindClass("android/graphics/Bitmap$Config");
- if (configClazz == NULL) {
+ clazz.reset(env->FindClass("android/graphics/Bitmap$Config"));
+ if (clazz.get() == NULL) {
return;
}
- fields.configClazz = (jclass) env->NewGlobalRef(configClazz);
+ fields.configClazz = (jclass) env->NewGlobalRef(clazz.get());
if (fields.configClazz == NULL) {
return;
}
@@ -535,6 +593,42 @@ static void android_media_MediaMetadataRetriever_native_init(JNIEnv *env)
if (fields.createConfigMethod == NULL) {
return;
}
+
+ clazz.reset(env->FindClass("android/media/MediaMetadataRetriever$BitmapParams"));
+ if (clazz.get() == NULL) {
+ return;
+ }
+ fields.bitmapParamsClazz = (jclass) env->NewGlobalRef(clazz.get());
+ if (fields.bitmapParamsClazz == NULL) {
+ return;
+ }
+ fields.inPreferredConfig = env->GetFieldID(fields.bitmapParamsClazz,
+ "inPreferredConfig", "Landroid/graphics/Bitmap$Config;");
+ if (fields.inPreferredConfig == NULL) {
+ return;
+ }
+ fields.outActualConfig = env->GetFieldID(fields.bitmapParamsClazz,
+ "outActualConfig", "Landroid/graphics/Bitmap$Config;");
+ if (fields.outActualConfig == NULL) {
+ return;
+ }
+
+ clazz.reset(env->FindClass("java/util/ArrayList"));
+ if (clazz.get() == NULL) {
+ return;
+ }
+ fields.arrayListClazz = (jclass) env->NewGlobalRef(clazz.get());
+ if (fields.arrayListClazz == NULL) {
+ return;
+ }
+ fields.arrayListInit = env->GetMethodID(clazz.get(), "", "()V");
+ if (fields.arrayListInit == NULL) {
+ return;
+ }
+ fields.arrayListAdd = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
+ if (fields.arrayListAdd == NULL) {
+ return;
+ }
}
static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobject thiz)
@@ -556,17 +650,36 @@ static const JNINativeMethod nativeMethods[] = {
(void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders
},
- {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
- {"_setDataSource", "(Landroid/media/MediaDataSource;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
- {"_getFrameAtTime", "(JIII)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
- {"_getImageAtIndex", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getImageAtIndex},
- {"_getFrameAtIndex", "(II)[Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtIndex},
- {"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
- {"getEmbeddedPicture", "(I)[B", (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},
- {"release", "()V", (void *)android_media_MediaMetadataRetriever_release},
- {"native_finalize", "()V", (void *)android_media_MediaMetadataRetriever_native_finalize},
- {"native_setup", "()V", (void *)android_media_MediaMetadataRetriever_native_setup},
- {"native_init", "()V", (void *)android_media_MediaMetadataRetriever_native_init},
+ {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
+ (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
+ {"_setDataSource", "(Landroid/media/MediaDataSource;)V",
+ (void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
+ {"_getFrameAtTime", "(JIII)Landroid/graphics/Bitmap;",
+ (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
+ {
+ "_getImageAtIndex",
+ "(ILandroid/media/MediaMetadataRetriever$BitmapParams;)Landroid/graphics/Bitmap;",
+ (void *)android_media_MediaMetadataRetriever_getImageAtIndex
+ },
+
+ {
+ "_getFrameAtIndex",
+ "(IILandroid/media/MediaMetadataRetriever$BitmapParams;)Ljava/util/List;",
+ (void *)android_media_MediaMetadataRetriever_getFrameAtIndex
+ },
+
+ {"extractMetadata", "(I)Ljava/lang/String;",
+ (void *)android_media_MediaMetadataRetriever_extractMetadata},
+ {"getEmbeddedPicture", "(I)[B",
+ (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},
+ {"release", "()V",
+ (void *)android_media_MediaMetadataRetriever_release},
+ {"native_finalize", "()V",
+ (void *)android_media_MediaMetadataRetriever_native_finalize},
+ {"native_setup", "()V",
+ (void *)android_media_MediaMetadataRetriever_native_setup},
+ {"native_init", "()V",
+ (void *)android_media_MediaMetadataRetriever_native_init},
};
// This function only registers the native methods, and is called from
--
GitLab
From e3aad1c076cd5ac1b1c5496597bfce3619dd50ff Mon Sep 17 00:00:00 2001
From: David Zeuthen
Date: Mon, 12 Mar 2018 16:47:03 -0400
Subject: [PATCH 091/488] ConfirmationDialog: Fail if accessibility services
are running.
As the confirmation dialog only has limited accessibility support it
may not be usable by users requiring accessibility services.
Therefore, if the user has enabled accessibility services, fail with
ConfirmationNotAvailableException so the application can handle this
case. Also document this behavior.
Bug: 74545109
Test: Manually tested.
Change-Id: Ibfb80d217f5cbdc9ec2f4e0432dfdd88add69703
---
.../android/security/ConfirmationDialog.java | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/core/java/android/security/ConfirmationDialog.java b/core/java/android/security/ConfirmationDialog.java
index f6127e18413..1697106c378 100644
--- a/core/java/android/security/ConfirmationDialog.java
+++ b/core/java/android/security/ConfirmationDialog.java
@@ -227,12 +227,32 @@ public class ConfirmationDialog {
return uiOptionsAsFlags;
}
+ private boolean isAccessibilityServiceRunning() {
+ boolean serviceRunning = false;
+ try {
+ ContentResolver contentResolver = mContext.getContentResolver();
+ int a11yEnabled = Settings.Secure.getInt(contentResolver,
+ Settings.Secure.ACCESSIBILITY_ENABLED);
+ if (a11yEnabled == 1) {
+ serviceRunning = true;
+ }
+ } catch (SettingNotFoundException e) {
+ Log.w(TAG, "Unexpected SettingNotFoundException");
+ e.printStackTrace();
+ }
+ return serviceRunning;
+ }
+
/**
* Requests a confirmation prompt to be presented to the user.
*
* When the prompt is no longer being presented, one of the methods in
* {@link ConfirmationCallback} is called on the supplied callback object.
*
+ * Confirmation dialogs may not be available when accessibility services are running so this
+ * may fail with a {@link ConfirmationNotAvailableException} exception even if
+ * {@link #isSupported} returns {@code true}.
+ *
* @param executor the executor identifying the thread that will receive the callback.
* @param callback the callback to use when the dialog is done showing.
* @throws IllegalArgumentException if the prompt text is too long or malfomed.
@@ -245,6 +265,9 @@ public class ConfirmationDialog {
if (mCallback != null) {
throw new ConfirmationAlreadyPresentingException();
}
+ if (isAccessibilityServiceRunning()) {
+ throw new ConfirmationNotAvailableException();
+ }
mCallback = callback;
mExecutor = executor;
--
GitLab
From a43867501e286d8f123d63eb759ffd42471a32c6 Mon Sep 17 00:00:00 2001
From: Julia Reynolds
Date: Mon, 12 Mar 2018 14:07:04 -0400
Subject: [PATCH 092/488] Volume UI updates
- redline compliance
- a11y labeling
- hide setting icon if device isn't provisioned
Change-Id: I62e0da51879dc5f6e05ed814f2d9b6ee41e125a1
Fixes: 74152268
Fixes: 73963013
Fixes: 73902271
Test: manual inspection
---
core/res/res/values/themes_device_defaults.xml | 3 +++
.../res/drawable/rounded_bg_bottom_background.xml | 2 +-
packages/SystemUI/res/layout/volume_dialog.xml | 8 +++++---
.../SystemUI/res/layout/volume_dialog_row.xml | 4 +++-
packages/SystemUI/res/values/dimens.xml | 10 ++++++++--
packages/SystemUI/res/values/strings.xml | 3 +++
.../android/systemui/volume/VolumeDialogImpl.java | 15 ++++++++++++---
.../SysuiDarkThemeOverlay/res/values/styles.xml | 1 +
8 files changed, 36 insertions(+), 10 deletions(-)
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index fdbcd8a27f9..25b053b0f0c 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1318,6 +1318,9 @@ easier.
@color/config_progress_background_tint@dimen/config_progressBarCornerRadius
+
+
+ @color/primary_material_light
\ No newline at end of file
--
GitLab
From ef9225e061a5341d0254606df33d9db317179c78 Mon Sep 17 00:00:00 2001
From: Felipe Leme
Date: Mon, 12 Mar 2018 14:56:42 -0700
Subject: [PATCH 093/488] Fixed flags when button that trigger autofill is
clicked.
Test: atest CtsAutoFillServiceTestCases:SimpleSaveActivityTest#testExplicitySaveButton
Test: manual observation
Fixes: 72937886
Change-Id: Iad8ee6ff6540b07137c8e90c7bb6e77a9fe27a7c
---
core/java/android/view/View.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index bf0e2ebf6de..b624870deb9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6546,7 +6546,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} finally {
// Set it to already called so it's not called twice when called by
// performClickInternal()
- mPrivateFlags |= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK;
+ mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK;
}
}
}
--
GitLab
From 34942ab7b18b1f2209b4be143c5971bbc256c4f7 Mon Sep 17 00:00:00 2001
From: Tony Mak
Date: Tue, 6 Mar 2018 11:24:51 +0000
Subject: [PATCH 094/488] Use the correct drawable to badge user icon
Also, ic_corp_user_badge is now tinted by default color, insteaad
on white by default.
Test: Create managed user, observe the icon is now blue on white.
Test: Wifi data usage, observe the icon of "All work apps" are now
grey instead of white.
FIXES: 71568987
Merged-In:Ic6c8ed15644c6e7894f2a84320077a3962603b5b
Change-Id: Ic6c8ed15644c6e7894f2a84320077a3962603b5b
---
core/res/res/drawable/ic_corp_user_badge.xml | 3 ++-
.../src/com/android/settingslib/Utils.java | 3 +--
.../drawable/UserIconDrawable.java | 25 +++++++++++++------
3 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/core/res/res/drawable/ic_corp_user_badge.xml b/core/res/res/drawable/ic_corp_user_badge.xml
index 6a0d9025684..a08f2d4845e 100644
--- a/core/res/res/drawable/ic_corp_user_badge.xml
+++ b/core/res/res/drawable/ic_corp_user_badge.xml
@@ -2,7 +2,8 @@
android:width="36dp"
android:height="36dp"
android:viewportWidth="36.0"
- android:viewportHeight="36.0">
+ android:viewportHeight="36.0"
+ android:tint="?attr/colorControlNormal">
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 61e113b3e39..56a242aea6a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -1,7 +1,6 @@
package com.android.settingslib;
import android.annotation.ColorInt;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
@@ -142,7 +141,7 @@ public class Utils {
public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
final int iconSize = UserIconDrawable.getSizeForList(context);
if (user.isManagedProfile()) {
- Drawable drawable = UserIconDrawable.getManagedUserBadgeDrawable(context);
+ Drawable drawable = UserIconDrawable.getManagedUserDrawable(context);
drawable.setBounds(0, 0, iconSize, iconSize);
return drawable;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
index 7f469b5e749..54d1aba09ae 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
@@ -16,6 +16,7 @@
package com.android.settingslib.drawable;
+import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
@@ -36,6 +37,7 @@ import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
import com.android.settingslib.R;
@@ -69,15 +71,23 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback {
private float mBadgeMargin;
/**
- * Gets the system default managed-user badge as a drawable
+ * Gets the system default managed-user badge as a drawable. This drawable is tint-able.
+ * For badging purpose, consider
+ * {@link android.content.pm.PackageManager#getUserBadgedDrawableForDensity(Drawable, UserHandle, Rect, int)}.
+ *
* @param context
* @return drawable containing just the badge
*/
- public static Drawable getManagedUserBadgeDrawable(Context context) {
- int displayDensity = context.getResources().getDisplayMetrics().densityDpi;
+ public static Drawable getManagedUserDrawable(Context context) {
+ return getDrawableForDisplayDensity
+ (context, com.android.internal.R.drawable.ic_corp_user_badge);
+ }
+
+ private static Drawable getDrawableForDisplayDensity(
+ Context context, @DrawableRes int drawable) {
+ int density = context.getResources().getDisplayMetrics().densityDpi;
return context.getResources().getDrawableForDensity(
- com.android.internal.R.drawable.ic_corp_user_badge,
- displayDensity, context.getTheme());
+ drawable, density, context.getTheme());
}
/**
@@ -164,7 +174,8 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback {
boolean isManaged = context.getSystemService(DevicePolicyManager.class)
.getProfileOwnerAsUser(userId) != null;
if (isManaged) {
- badge = getManagedUserBadgeDrawable(context);
+ badge = getDrawableForDisplayDensity(
+ context, com.android.internal.R.drawable.ic_corp_badge_case);
}
return setBadge(badge);
}
@@ -322,7 +333,6 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback {
mIntrinsicRadius, mIconPaint);
canvas.restoreToCount(saveId);
}
-
if (mFrameColor != null) {
mFramePaint.setColor(mFrameColor.getColorForState(getState(), Color.TRANSPARENT));
}
@@ -343,7 +353,6 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback {
final float borderRadius = mBadge.getBounds().width() * 0.5f + mBadgeMargin;
canvas.drawCircle(badgeLeft + mBadgeRadius, badgeTop + mBadgeRadius,
borderRadius, mClearPaint);
-
mBadge.draw(canvas);
}
}
--
GitLab
From 39a5e09440df28417c2d031c83f9acf5527e0c02 Mon Sep 17 00:00:00 2001
From: jovanak
Date: Fri, 9 Mar 2018 15:31:44 -0800
Subject: [PATCH 095/488] Removing the countdown timer and countdown progress
bar from the Car User Picker.
For now, this means we stay on this page until the user makes a selection.
Change-Id: I84c098f9aacd587e2a75e1be8851a830e685dba6
Fixes: 74445361
Bug: 73499223
Test: Tested on mojave. No automated tests for the switcher yet.
---
.../layout/car_fullscreen_user_switcher.xml | 12 +----
packages/SystemUI/res/layout/car_qs_panel.xml | 1 -
packages/SystemUI/res/values/dimens_car.xml | 3 --
packages/SystemUI/res/values/integers_car.xml | 3 --
packages/SystemUI/res/values/styles_car.xml | 8 ---
.../statusbar/car/FullscreenUserSwitcher.java | 49 -------------------
6 files changed, 1 insertion(+), 75 deletions(-)
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
index 478b6564268..bfabe520ef4 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -39,23 +39,13 @@
android:theme="@android:style/Theme"
android:layout_alignParentTop="true"/>
-
-
-
+ android:layout_centerInParent="true"/>
12dp
24dp
- 6dp
- @dimen/status_bar_height16dp30dp80dp
@@ -57,7 +55,6 @@
420dp-420dp
- 28dp26sp
diff --git a/packages/SystemUI/res/values/integers_car.xml b/packages/SystemUI/res/values/integers_car.xml
index f84dd4bd5f2..a462576c48d 100644
--- a/packages/SystemUI/res/values/integers_car.xml
+++ b/packages/SystemUI/res/values/integers_car.xml
@@ -16,8 +16,5 @@
-->
- 15000
-
- 6027
diff --git a/packages/SystemUI/res/values/styles_car.xml b/packages/SystemUI/res/values/styles_car.xml
index c66792ca6a1..2aaef86296f 100644
--- a/packages/SystemUI/res/values/styles_car.xml
+++ b/packages/SystemUI/res/values/styles_car.xml
@@ -16,14 +16,6 @@
-->
-
-
+
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index be28d8cea77..4001f9e04a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -139,6 +139,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private boolean mSensitiveHiddenInGeneral;
private boolean mShowingPublicInitialized;
private boolean mHideSensitiveForIntrinsicHeight;
+ private float mHeaderVisibleAmount = 1.0f;
/**
* Is this notification expanded by the system. The expansion state can be overridden by the
@@ -156,8 +157,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private NotificationContentView mPublicLayout;
private NotificationContentView mPrivateLayout;
private NotificationContentView[] mLayouts;
- private int mMaxExpandHeight;
- private int mHeadsUpHeight;
private int mNotificationColor;
private ExpansionLogger mLogger;
private String mLoggingKey;
@@ -534,6 +533,30 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
addChildNotification(row, -1);
}
+ /**
+ * Set the how much the header should be visible. A value of 0 will make the header fully gone
+ * and a value of 1 will make the notification look just like normal.
+ * This is being used for heads up notifications, when they are pinned to the top of the screen
+ * and the header content is extracted to the statusbar.
+ *
+ * @param headerVisibleAmount the amount the header should be visible.
+ */
+ public void setHeaderVisibleAmount(float headerVisibleAmount) {
+ if (mHeaderVisibleAmount != headerVisibleAmount) {
+ mHeaderVisibleAmount = headerVisibleAmount;
+ mPrivateLayout.setHeaderVisibleAmount(headerVisibleAmount);
+ if (mChildrenContainer != null) {
+ mChildrenContainer.setHeaderVisibleAmount(headerVisibleAmount);
+ }
+ notifyHeightChanged(false /* needsAnimation */);
+ }
+ }
+
+ @VisibleForTesting
+ public float getHeaderVisibleAmount() {
+ return mHeaderVisibleAmount;
+ }
+
@Override
public void setHeadsUpIsVisible() {
super.setHeadsUpIsVisible();
@@ -742,11 +765,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mChildrenContainer.getIntrinsicHeight();
}
if(mExpandedWhenPinned) {
- return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
+ return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
} else if (atLeastMinHeight) {
- return Math.max(getCollapsedHeight(), mHeadsUpHeight);
+ return Math.max(getCollapsedHeight(), getHeadsUpHeight());
} else {
- return mHeadsUpHeight;
+ return getHeadsUpHeight();
}
}
@@ -1923,9 +1946,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
if (isPinned() || mHeadsupDisappearRunning) {
return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
} else if (isExpanded()) {
- return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
+ return Math.max(getMaxExpandHeight(), getHeadsUpHeight());
} else {
- return Math.max(getCollapsedHeight(), mHeadsUpHeight);
+ return Math.max(getCollapsedHeight(), getHeadsUpHeight());
}
} else if (isExpanded()) {
return getMaxExpandHeight();
@@ -1999,8 +2022,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ int intrinsicBefore = getIntrinsicHeight();
super.onLayout(changed, left, top, right, bottom);
- updateMaxHeights();
+ if (intrinsicBefore != getIntrinsicHeight()) {
+ notifyHeightChanged(true /* needsAnimation */);
+ }
if (mMenuRow.getMenuView() != null) {
mMenuRow.onHeightUpdate();
}
@@ -2024,15 +2050,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
- public void updateMaxHeights() {
- int intrinsicBefore = getIntrinsicHeight();
- mMaxExpandHeight = mPrivateLayout.getExpandHeight();
- mHeadsUpHeight = mPrivateLayout.getHeadsUpHeight();
- if (intrinsicBefore != getIntrinsicHeight()) {
- notifyHeightChanged(true /* needsAnimation */);
- }
- }
-
@Override
public void notifyHeightChanged(boolean needsAnimation) {
super.notifyHeightChanged(needsAnimation);
@@ -2175,7 +2192,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
public int getMaxExpandHeight() {
- return mMaxExpandHeight;
+ return mPrivateLayout.getExpandHeight();
+ }
+
+
+ private int getHeadsUpHeight() {
+ return mPrivateLayout.getHeadsUpHeight();
}
public boolean areGutsExposed() {
@@ -2275,7 +2297,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
} else if (mIsSummaryWithChildren && !isGroupExpanded() && !shouldShowPublic()) {
return mChildrenContainer.getMinHeight();
} else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp) {
- return mHeadsUpHeight;
+ return getHeadsUpHeight();
}
NotificationContentView showingLayout = getShowingLayout();
return showingLayout.getMinHeight();
@@ -2321,10 +2343,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
- public boolean isMaxExpandHeightInitialized() {
- return mMaxExpandHeight != 0;
- }
-
public NotificationContentView getShowingLayout() {
return shouldShowPublic() ? mPublicLayout : mPrivateLayout;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
new file mode 100644
index 00000000000..9977fe95d5c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.AlphaOptimizedLinearLayout;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+
+/**
+ * The view in the statusBar that contains part of the heads-up information
+ */
+public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
+ private int mAbsoluteStartPadding;
+ private int mEndMargin;
+ private View mIconPlaceholder;
+ private TextView mTextView;
+ private NotificationData.Entry mShowingEntry;
+ private Rect mIconRect = new Rect();
+ private int[] mTmpPosition = new int[2];
+ private boolean mFirstLayout = true;
+ private boolean mPublicMode;
+
+ public HeadsUpStatusBarView(Context context) {
+ this(context, null);
+ }
+
+ public HeadsUpStatusBarView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public HeadsUpStatusBarView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public HeadsUpStatusBarView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ Resources res = getResources();
+ mAbsoluteStartPadding = res.getDimensionPixelSize(R.dimen.notification_side_paddings)
+ + res.getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_start);
+ mEndMargin = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_end);
+ setPaddingRelative(mAbsoluteStartPadding, 0, mEndMargin, 0);
+ }
+
+ @VisibleForTesting
+ public HeadsUpStatusBarView(Context context, View iconPlaceholder, TextView textView) {
+ this(context);
+ mIconPlaceholder = iconPlaceholder;
+ mTextView = textView;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mIconPlaceholder = findViewById(R.id.icon_placeholder);
+ mTextView = findViewById(R.id.text);
+ }
+
+ public void setEntry(NotificationData.Entry entry) {
+ if (entry != null) {
+ mShowingEntry = entry;
+ CharSequence text = entry.headsUpStatusBarText;
+ if (mPublicMode) {
+ text = entry.headsUpStatusBarTextPublic;
+ }
+ mTextView.setText(text);
+ } else {
+ mShowingEntry = null;
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ mIconPlaceholder.getLocationOnScreen(mTmpPosition);
+ int left = mTmpPosition[0];
+ int top = mTmpPosition[1];
+ int right = left + mIconPlaceholder.getWidth();
+ int bottom = top + mIconPlaceholder.getHeight();
+ mIconRect.set(left, top, right, bottom);
+ if (left != mAbsoluteStartPadding) {
+ int newPadding = mAbsoluteStartPadding - left + getPaddingStart();
+ setPaddingRelative(newPadding, 0, mEndMargin, 0);
+ }
+ if (mFirstLayout) {
+ // we need to do the padding calculation in the first frame, so the layout specified
+ // our visibility to be INVISIBLE in the beginning. let's correct that and set it
+ // to GONE.
+ setVisibility(GONE);
+ mFirstLayout = false;
+ }
+ }
+
+ public NotificationData.Entry getShowingEntry() {
+ return mShowingEntry;
+ }
+
+ public Rect getIconDrawingRect() {
+ return mIconRect;
+ }
+
+ public void onDarkChanged(Rect area, float darkIntensity, int tint) {
+ mTextView.setTextColor(DarkIconDispatcher.getTint(area, this, tint));
+ }
+
+ public void setPublicMode(boolean publicMode) {
+ mPublicMode = publicMode;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 73c87953cf4..f64b1bc2abe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -602,14 +602,15 @@ public class NotificationContentView extends FrameLayout {
&& (mIsHeadsUp || mHeadsUpAnimatingAway)
&& !mContainingNotification.isOnKeyguard();
if (transitioningBetweenHunAndExpanded || pinned) {
- return Math.min(mHeadsUpChild.getHeight(), mExpandedChild.getHeight());
+ return Math.min(getViewHeight(VISIBLE_TYPE_HEADSUP),
+ getViewHeight(VISIBLE_TYPE_EXPANDED));
}
}
// Size change of the expanded version
if ((mVisibleType == VISIBLE_TYPE_EXPANDED) && mContentHeightAtAnimationStart >= 0
&& mExpandedChild != null) {
- return Math.min(mContentHeightAtAnimationStart, mExpandedChild.getHeight());
+ return Math.min(mContentHeightAtAnimationStart, getViewHeight(VISIBLE_TYPE_EXPANDED));
}
int hint;
@@ -619,16 +620,17 @@ public class NotificationContentView extends FrameLayout {
VISIBLE_TYPE_AMBIENT_SINGLELINE)) {
hint = mAmbientSingleLineChild.getHeight();
} else if (mHeadsUpChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_HEADSUP)) {
- hint = mHeadsUpChild.getHeight();
+ hint = getViewHeight(VISIBLE_TYPE_HEADSUP);
} else if (mExpandedChild != null) {
- hint = mExpandedChild.getHeight();
+ hint = getViewHeight(VISIBLE_TYPE_EXPANDED);
} else {
- hint = mContractedChild.getHeight() + mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_action_list_height);
+ hint = getViewHeight(VISIBLE_TYPE_CONTRACTED)
+ + mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_action_list_height);
}
if (mExpandedChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_EXPANDED)) {
- hint = Math.min(hint, mExpandedChild.getHeight());
+ hint = Math.min(hint, getViewHeight(VISIBLE_TYPE_EXPANDED));
}
return hint;
}
@@ -694,8 +696,8 @@ public class NotificationContentView extends FrameLayout {
}
private float calculateTransformationAmount() {
- int startHeight = getViewForVisibleType(mTransformationStartVisibleType).getHeight();
- int endHeight = getViewForVisibleType(mVisibleType).getHeight();
+ int startHeight = getViewHeight(mTransformationStartVisibleType);
+ int endHeight = getViewHeight(mVisibleType);
int progress = Math.abs(mContentHeight - startHeight);
int totalDistance = Math.abs(endHeight - startHeight);
if (totalDistance == 0) {
@@ -717,11 +719,23 @@ public class NotificationContentView extends FrameLayout {
if (mContainingNotification.isShowingAmbient()) {
return getShowingAmbientView().getHeight();
} else if (mExpandedChild != null) {
- return mExpandedChild.getHeight() + getExtraRemoteInputHeight(mExpandedRemoteInput);
+ return getViewHeight(VISIBLE_TYPE_EXPANDED)
+ + getExtraRemoteInputHeight(mExpandedRemoteInput);
} else if (mIsHeadsUp && mHeadsUpChild != null && !mContainingNotification.isOnKeyguard()) {
- return mHeadsUpChild.getHeight() + getExtraRemoteInputHeight(mHeadsUpRemoteInput);
+ return getViewHeight(VISIBLE_TYPE_HEADSUP)
+ + getExtraRemoteInputHeight(mHeadsUpRemoteInput);
}
- return mContractedChild.getHeight();
+ return getViewHeight(VISIBLE_TYPE_CONTRACTED);
+ }
+
+ private int getViewHeight(int visibleType) {
+ View view = getViewForVisibleType(visibleType);
+ int height = view.getHeight();
+ NotificationViewWrapper viewWrapper = getWrapperForView(view);
+ if (viewWrapper != null) {
+ height += viewWrapper.getHeaderTranslation();
+ }
+ return height;
}
public int getMinHeight() {
@@ -732,7 +746,7 @@ public class NotificationContentView extends FrameLayout {
if (mContainingNotification.isShowingAmbient()) {
return getShowingAmbientView().getHeight();
} else if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
- return mContractedChild.getHeight();
+ return getViewHeight(VISIBLE_TYPE_CONTRACTED);
} else {
return mSingleLineView.getHeight();
}
@@ -1046,7 +1060,7 @@ public class NotificationContentView extends FrameLayout {
private int getVisualTypeForHeight(float viewHeight) {
boolean noExpandedChild = mExpandedChild == null;
- if (!noExpandedChild && viewHeight == mExpandedChild.getHeight()) {
+ if (!noExpandedChild && viewHeight == getViewHeight(VISIBLE_TYPE_EXPANDED)) {
return VISIBLE_TYPE_EXPANDED;
}
if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) {
@@ -1055,13 +1069,13 @@ public class NotificationContentView extends FrameLayout {
if ((mIsHeadsUp || mHeadsUpAnimatingAway) && mHeadsUpChild != null
&& !mContainingNotification.isOnKeyguard()) {
- if (viewHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
+ if (viewHeight <= getViewHeight(VISIBLE_TYPE_HEADSUP) || noExpandedChild) {
return VISIBLE_TYPE_HEADSUP;
} else {
return VISIBLE_TYPE_EXPANDED;
}
} else {
- if (noExpandedChild || (viewHeight <= mContractedChild.getHeight()
+ if (noExpandedChild || (viewHeight <= getViewHeight(VISIBLE_TYPE_CONTRACTED)
&& (!mIsChildInGroup || isGroupExpanded()
|| !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) {
return VISIBLE_TYPE_CONTRACTED;
@@ -1616,19 +1630,19 @@ public class NotificationContentView extends FrameLayout {
}
public int getExpandHeight() {
- View expandedChild = mExpandedChild;
- if (expandedChild == null) {
- expandedChild = mContractedChild;
+ int viewType = VISIBLE_TYPE_EXPANDED;
+ if (mExpandedChild == null) {
+ viewType = VISIBLE_TYPE_CONTRACTED;
}
- return expandedChild.getHeight() + getExtraRemoteInputHeight(mExpandedRemoteInput);
+ return getViewHeight(viewType) + getExtraRemoteInputHeight(mExpandedRemoteInput);
}
public int getHeadsUpHeight() {
- View headsUpChild = mHeadsUpChild;
- if (headsUpChild == null) {
- headsUpChild = mContractedChild;
+ int viewType = VISIBLE_TYPE_HEADSUP;
+ if (mHeadsUpChild == null) {
+ viewType = VISIBLE_TYPE_CONTRACTED;
}
- return headsUpChild.getHeight()+ getExtraRemoteInputHeight(mHeadsUpRemoteInput);
+ return getViewHeight(viewType) + getExtraRemoteInputHeight(mHeadsUpRemoteInput);
}
public void setRemoteInputVisible(boolean remoteInputVisible) {
@@ -1641,4 +1655,16 @@ public class NotificationContentView extends FrameLayout {
clipChildren = clipChildren && !mRemoteInputVisible;
super.setClipChildren(clipChildren);
}
+
+ public void setHeaderVisibleAmount(float headerVisibleAmount) {
+ if (mContractedWrapper != null) {
+ mContractedWrapper.setHeaderVisibleAmount(headerVisibleAmount);
+ }
+ if (mHeadsUpWrapper != null) {
+ mHeadsUpWrapper.setHeaderVisibleAmount(headerVisibleAmount);
+ }
+ if (mExpandedWrapper != null) {
+ mExpandedWrapper.setHeaderVisibleAmount(headerVisibleAmount);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 22a186ff170..ebd22610b52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -107,6 +107,8 @@ public class NotificationData {
public CharSequence remoteInputTextWhenReset;
public long lastRemoteInputSent = NOT_LAUNCHED_YET;
public ArraySet mActiveAppOps = new ArraySet<>(3);
+ public CharSequence headsUpStatusBarText;
+ public CharSequence headsUpStatusBarTextPublic;
public Entry(StatusBarNotification n) {
this.key = n.getKey();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 4f09133303d..abcdef3e734 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -252,7 +252,8 @@ public class NotificationShelf extends ActivatableNotificationView implements
}
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
float notificationClipEnd;
- boolean aboveShelf = ViewState.getFinalTranslationZ(row) > baseZHeight;
+ boolean aboveShelf = ViewState.getFinalTranslationZ(row) > baseZHeight
+ || row.isPinned();
boolean isLastChild = child == lastChild;
float rowTranslationY = row.getTranslationY();
if ((isLastChild && !child.isInShelf()) || aboveShelf || backgroundForceHidden) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index dfcd5e60719..251e04b01af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -52,6 +52,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
protected final ViewInvertHelper mInvertHelper;
protected final ViewTransformationHelper mTransformationHelper;
+ private final int mTranslationForHeader;
protected int mColor;
private ImageView mIcon;
@@ -63,6 +64,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
private boolean mIsLowPriority;
private boolean mTransformLowPriorityTitle;
private boolean mShowExpandButtonAtEnd;
+ protected float mHeaderTranslation;
protected NotificationHeaderViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
super(ctx, view, row);
@@ -99,6 +101,10 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
resolveHeaderViews();
updateInvertHelper();
addAppOpsOnClickListener(row);
+ mTranslationForHeader = ctx.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin)
+ - ctx.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_top);
}
@Override
@@ -242,6 +248,19 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
}
+ @Override
+ public void setHeaderVisibleAmount(float headerVisibleAmount) {
+ super.setHeaderVisibleAmount(headerVisibleAmount);
+ mNotificationHeader.setAlpha(headerVisibleAmount);
+ mHeaderTranslation = (1.0f - headerVisibleAmount) * mTranslationForHeader;
+ mView.setTranslationY(mHeaderTranslation);
+ }
+
+ @Override
+ public int getHeaderTranslation() {
+ return (int) mHeaderTranslation;
+ }
+
@Override
public NotificationHeaderView getNotificationHeader() {
return mNotificationHeader;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
index f9671182ab8..f5110a2dbc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
@@ -179,6 +179,9 @@ public class NotificationInflater {
: builder.makeAmbientNotification();
}
result.packageContext = packageContext;
+ result.headsUpStatusBarText = builder.getHeadsUpStatusBarText(false /* showingPublic */);
+ result.headsUpStatusBarTextPublic = builder.getHeadsUpStatusBarText(
+ true /* showingPublic */);
return result;
}
@@ -456,6 +459,8 @@ public class NotificationInflater {
}
entry.cachedAmbientContentView = result.newAmbientView;
}
+ entry.headsUpStatusBarText = result.headsUpStatusBarText;
+ entry.headsUpStatusBarTextPublic = result.headsUpStatusBarTextPublic;
if (endListener != null) {
endListener.onAsyncInflationFinished(row.getEntry());
}
@@ -665,6 +670,8 @@ public class NotificationInflater {
private View inflatedExpandedView;
private View inflatedAmbientView;
private View inflatedPublicView;
+ private CharSequence headsUpStatusBarText;
+ private CharSequence headsUpStatusBarTextPublic;
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index d463eae6e43..28beb21dba4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -278,7 +278,10 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
if (mActionsContainer != null) {
// We should never push the actions higher than they are in the headsup view.
int constrainedContentHeight = Math.max(mContentHeight, mMinHeightHint);
- mActionsContainer.setTranslationY(constrainedContentHeight - mView.getHeight());
+
+ // We also need to compensate for any header translation, since we're always at the end.
+ mActionsContainer.setTranslationY(constrainedContentHeight - mView.getHeight()
+ - getHeaderTranslation());
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 17eb4c11003..873f088f843 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -133,6 +133,10 @@ public abstract class NotificationViewWrapper implements TransformableView {
return null;
}
+ public int getHeaderTranslation() {
+ return 0;
+ }
+
@Override
public TransformState getCurrentState(int fadingView) {
return null;
@@ -198,4 +202,7 @@ public abstract class NotificationViewWrapper implements TransformableView {
public boolean shouldClipToRounding(boolean topRounded, boolean bottomRounded) {
return false;
}
+
+ public void setHeaderVisibleAmount(float headerVisibleAmount) {
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
new file mode 100644
index 00000000000..cd97c05ede2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.graphics.Rect;
+import android.service.notification.StatusBarNotification;
+import android.util.EventLog;
+import android.util.Log;
+import android.view.View;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.HeadsUpStatusBarView;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+
+import java.util.stream.Stream;
+
+/**
+ * Controls the appearance of heads up notifications in the icon area and the header itself.
+ */
+class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
+ DarkIconDispatcher.DarkReceiver {
+ private final NotificationIconAreaController mNotificationIconAreaController;
+ private final HeadsUpManagerPhone mHeadsUpManager;
+ private final NotificationStackScrollLayout mStackScroller;
+ private final HeadsUpStatusBarView mHeadsUpStatusBarView;
+ private final View mClockView;
+ private final DarkIconDispatcher mDarkIconDispatcher;
+ private float mExpandedHeight;
+ private boolean mIsExpanded;
+ private float mExpandFraction;
+ private ExpandableNotificationRow mTrackedChild;
+ private boolean mShown;
+
+ public HeadsUpAppearanceController(
+ NotificationIconAreaController notificationIconAreaController,
+ HeadsUpManagerPhone headsUpManager,
+ View statusbarView) {
+ this(notificationIconAreaController, headsUpManager,
+ statusbarView.findViewById(R.id.heads_up_status_bar_view),
+ statusbarView.findViewById(R.id.notification_stack_scroller),
+ statusbarView.findViewById(R.id.notification_panel),
+ statusbarView.findViewById(R.id.clock));
+ }
+
+ @VisibleForTesting
+ public HeadsUpAppearanceController(
+ NotificationIconAreaController notificationIconAreaController,
+ HeadsUpManagerPhone headsUpManager,
+ HeadsUpStatusBarView headsUpStatusBarView,
+ NotificationStackScrollLayout stackScroller,
+ NotificationPanelView panelView,
+ View clockView) {
+ mNotificationIconAreaController = notificationIconAreaController;
+ mHeadsUpManager = headsUpManager;
+ mHeadsUpManager.addListener(this);
+ mHeadsUpStatusBarView = headsUpStatusBarView;
+ mStackScroller = stackScroller;
+ panelView.addTrackingHeadsUpListener(this::setTrackingHeadsUp);
+ mStackScroller.addOnExpandedHeightListener(this::setExpandedHeight);
+ mClockView = clockView;
+ mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
+ mDarkIconDispatcher.addDarkReceiver(this);
+ }
+
+ @Override
+ public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
+ updateTopEntry();
+ updateHeader(headsUp.getEntry());
+ }
+
+ private void updateTopEntry() {
+ NotificationData.Entry newEntry = null;
+ if (!mIsExpanded && mHeadsUpManager.hasPinnedHeadsUp()) {
+ newEntry = mHeadsUpManager.getTopEntry();
+ }
+ NotificationData.Entry previousEntry = mHeadsUpStatusBarView.getShowingEntry();
+ mHeadsUpStatusBarView.setEntry(newEntry);
+ if (newEntry != previousEntry) {
+ if (newEntry == null) {
+ // no heads up anymore, lets start the disappear animation
+
+ setShown(false);
+ } else if (previousEntry == null) {
+ // We now have a headsUp and didn't have one before. Let's start the disappear
+ // animation
+ setShown(true);
+ }
+ mNotificationIconAreaController.showIconIsolated(newEntry == null ? null
+ : newEntry.icon, mHeadsUpStatusBarView.getIconDrawingRect());
+ }
+ }
+
+ private void setShown(boolean isShown) {
+ mShown = isShown;
+ mHeadsUpStatusBarView.setVisibility(isShown ? View.VISIBLE : View.GONE);
+ mClockView.setVisibility(!isShown ? View.VISIBLE : View.INVISIBLE);
+ }
+
+ @VisibleForTesting
+ public boolean isShown() {
+ return mShown;
+ }
+
+ @Override
+ public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
+ updateTopEntry();
+ updateHeader(headsUp.getEntry());
+ }
+
+ public void setExpandedHeight(float expandedHeight, float appearFraction) {
+ boolean changedHeight = expandedHeight != mExpandedHeight;
+ mExpandedHeight = expandedHeight;
+ mExpandFraction = appearFraction;
+ boolean isExpanded = expandedHeight > 0;
+ if (changedHeight) {
+ updateHeadsUpHeaders();
+ }
+ if (isExpanded != mIsExpanded) {
+ mIsExpanded = isExpanded;
+ updateTopEntry();
+ }
+ }
+
+ /**
+ * Set a headsUp to be tracked, meaning that it is currently being pulled down after being
+ * in a pinned state on the top. The expand animation is different in that case and we need
+ * to update the header constantly afterwards.
+ *
+ * @param trackedChild the tracked headsUp or null if it's not tracking anymore.
+ */
+ public void setTrackingHeadsUp(ExpandableNotificationRow trackedChild) {
+ ExpandableNotificationRow previousTracked = mTrackedChild;
+ mTrackedChild = trackedChild;
+ if (previousTracked != null) {
+ updateHeader(previousTracked.getEntry());
+ }
+ }
+
+ private void updateHeadsUpHeaders() {
+ mHeadsUpManager.getAllEntries().forEach(entry -> {
+ updateHeader(entry);
+ });
+ }
+
+ private void updateHeader(NotificationData.Entry entry) {
+ ExpandableNotificationRow row = entry.row;
+ float headerVisibleAmount = 1.0f;
+ if (row.isPinned() || row == mTrackedChild) {
+ headerVisibleAmount = mExpandFraction;
+ }
+ row.setHeaderVisibleAmount(headerVisibleAmount);
+ }
+
+ @Override
+ public void onDarkChanged(Rect area, float darkIntensity, int tint) {
+ mHeadsUpStatusBarView.onDarkChanged(area, darkIntensity, tint);
+ }
+
+ public void setPublicMode(boolean publicMode) {
+ mHeadsUpStatusBarView.setPublicMode(publicMode);
+ updateTopEntry();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index d2cdc27d982..fa0a774c249 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -29,6 +29,7 @@ import android.view.ViewTreeObserver;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
+import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
@@ -52,12 +53,13 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
private static final boolean DEBUG = false;
private final View mStatusBarWindowView;
- private int mStatusBarHeight;
private final NotificationGroupManager mGroupManager;
private final StatusBar mBar;
private final VisualStabilityManager mVisualStabilityManager;
-
private boolean mReleaseOnExpandFinish;
+
+ private int mStatusBarHeight;
+ private int mHeadsUpInset;
private boolean mTrackingHeadsUp;
private HashSet mSwipedOutKeys = new HashSet<>();
private HashSet mEntriesToRemoveAfterExpand = new HashSet<>();
@@ -101,9 +103,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
mBar = bar;
mVisualStabilityManager = visualStabilityManager;
- Resources resources = mContext.getResources();
- mStatusBarHeight = resources.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height);
+ initResources();
addListener(new OnHeadsUpChangedListener() {
@Override
@@ -114,6 +114,20 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
});
}
+ private void initResources() {
+ Resources resources = mContext.getResources();
+ mStatusBarHeight = resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height);
+ mHeadsUpInset = mStatusBarHeight + resources.getDimensionPixelSize(
+ R.dimen.heads_up_status_bar_padding);
+ }
+
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ super.onDensityOrFontScaleChanged();
+ initResources();
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////////
// Public methods:
@@ -283,10 +297,10 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
topEntry.getLocationOnScreen(mTmpTwoArray);
int minX = mTmpTwoArray[0];
int maxX = mTmpTwoArray[0] + topEntry.getWidth();
- int maxY = topEntry.getIntrinsicHeight();
+ int height = topEntry.getIntrinsicHeight();
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- info.touchableRegion.set(minX, 0, maxX, maxY);
+ info.touchableRegion.set(minX, 0, maxX, mHeadsUpInset + height);
} else if (mHeadsUpGoingAway || mWaitingOnCollapseWhenGoingAway) {
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 2bfdefe3901..903b8133986 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -23,7 +23,6 @@ import android.view.ViewConfiguration;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
/**
@@ -102,10 +101,11 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
mCollapseSnoozes = h < 0;
mInitialTouchX = x;
mInitialTouchY = y;
- int expandedHeight = mPickedChild.getActualHeight();
- mPanel.setPanelScrimMinFraction((float) expandedHeight
+ int startHeight = (int) (mPickedChild.getActualHeight()
+ + mPickedChild.getTranslationY());
+ mPanel.setPanelScrimMinFraction((float) startHeight
/ mPanel.getMaxPanelHeight());
- mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight);
+ mPanel.startExpandMotion(x, y, true /* startTracking */, startHeight);
mPanel.startExpandingFromPeek();
// This call needs to be after the expansion start otherwise we will get a
// flicker of one frame as it's not expanded yet.
@@ -135,7 +135,7 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
private void setTrackingHeadsUp(boolean tracking) {
mTrackingHeadsUp = tracking;
mHeadsUpManager.setTrackingHeadsUp(tracking);
- mPanel.setTrackingHeadsUp(tracking);
+ mPanel.setTrackedHeadsUp(tracking ? mPickedChild : null);
}
public void notifyFling(boolean collapse) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index e1aed7a04c3..51adebfd05c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -296,4 +296,8 @@ public class NotificationIconAreaController implements DarkReceiver {
mNotificationIcons.setDark(dark, false, 0);
mShelfIcons.setDark(dark, false, 0);
}
+
+ public void showIconIsolated(StatusBarIconView icon, Rect absoluteIconPosition) {
+ mNotificationIcons.showIconIsolated(icon, absoluteIconPosition);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index b29ac906755..53ae0f82b0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -21,12 +21,9 @@ import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.graphics.Rect;
import android.graphics.drawable.Icon;
-import android.os.AsyncTask;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
import android.support.v4.util.ArrayMap;
-import android.support.v4.util.ArraySet;
import android.util.AttributeSet;
import android.view.View;
@@ -127,6 +124,9 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
private float mVisualOverflowStart;
// Keep track of overflow in range [0, 3]
private int mNumDots;
+ private StatusBarIconView mIsolatedIcon;
+ private Rect mIsolatedIconLocation;
+ private int[] mAbsolutePosition = new int[2];
public NotificationIconContainer(Context context, AttributeSet attrs) {
@@ -196,13 +196,18 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
mIconSize = child.getWidth();
}
}
+ getLocationOnScreen(mAbsolutePosition);
if (mIsStaticLayout) {
- resetViewStates();
- calculateIconTranslations();
- applyIconStates();
+ updateState();
}
}
+ private void updateState() {
+ resetViewStates();
+ calculateIconTranslations();
+ applyIconStates();
+ }
+
public void applyIconStates() {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
@@ -306,7 +311,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
View view = getChildAt(i);
ViewState iconState = mIconStates.get(view);
iconState.initFrom(view);
- iconState.alpha = 1.0f;
+ iconState.alpha = mIsolatedIcon == null || view == mIsolatedIcon ? 1.0f : 0.0f;
iconState.hidden = false;
}
}
@@ -402,6 +407,16 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
iconState.xTranslation = getWidth() - iconState.xTranslation - view.getWidth();
}
}
+ if (mIsolatedIcon != null) {
+ IconState iconState = mIconStates.get(mIsolatedIcon);
+ if (iconState != null) {
+ // Most of the time the icon isn't yet added when this is called but only happening
+ // later
+ iconState.xTranslation = mIsolatedIconLocation.left - mAbsolutePosition[0]
+ - (1 - mIsolatedIcon.getIconScale()) * mIsolatedIcon.getWidth() / 2.0f;
+ iconState.visibleState = StatusBarIconView.STATE_ICON;
+ }
+ }
}
private float getLayoutEnd() {
@@ -573,6 +588,12 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
mReplacingIcons = replacingIcons;
}
+ public void showIconIsolated(StatusBarIconView icon, Rect absoluteIconPosition) {
+ mIsolatedIcon = icon;
+ mIsolatedIconLocation = absoluteIconPosition;
+ updateState();
+ }
+
public class IconState extends ViewState {
public static final int NO_VALUE = NotificationIconContainer.NO_VALUE;
public float iconAppearAmount = 1.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 2711d7ac7a8..63ee9ff684c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -74,7 +74,9 @@ import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;
+import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
public class NotificationPanelView extends PanelView implements
ExpandableView.OnHeightChangedListener,
@@ -243,6 +245,8 @@ public class NotificationPanelView extends PanelView implements
private float mExpandOffset;
private boolean mHideIconsDuringNotificationLaunch = true;
private int mStackScrollerMeasuringPass;
+ private ArrayList> mTrackingHeadsUpListeners
+ = new ArrayList<>();
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -269,6 +273,7 @@ public class NotificationPanelView extends PanelView implements
mNotificationStackScroller.setOnHeightChangedListener(this);
mNotificationStackScroller.setOverscrollTopChangedListener(this);
mNotificationStackScroller.setOnEmptySpaceClickListener(this);
+ addTrackingHeadsUpListener(mNotificationStackScroller::setTrackingHeadsUp);
mKeyguardBottomArea = findViewById(R.id.keyguard_bottom_area);
mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
mLastOrientation = getResources().getConfiguration().orientation;
@@ -1780,11 +1785,19 @@ public class NotificationPanelView extends PanelView implements
mQsExpandImmediate = false;
mTwoFingerQsExpandPossible = false;
mIsExpansionFromHeadsUp = false;
- mNotificationStackScroller.setTrackingHeadsUp(false);
+ notifyListenersTrackingHeadsUp(null);
mExpandingFromHeadsUp = false;
setPanelScrimMinFraction(0.0f);
}
+ private void notifyListenersTrackingHeadsUp(ExpandableNotificationRow pickedChild) {
+ for (int i = 0; i < mTrackingHeadsUpListeners.size(); i++) {
+ Consumer listener
+ = mTrackingHeadsUpListeners.get(i);
+ listener.accept(pickedChild);
+ }
+ }
+
private void setListening(boolean listening) {
mKeyguardStatusBar.setListening(listening);
if (mQs == null) return;
@@ -2351,9 +2364,9 @@ public class NotificationPanelView extends PanelView implements
this);
}
- public void setTrackingHeadsUp(boolean tracking) {
- if (tracking) {
- mNotificationStackScroller.setTrackingHeadsUp(true);
+ public void setTrackedHeadsUp(ExpandableNotificationRow pickedChild) {
+ if (pickedChild != null) {
+ notifyListenersTrackingHeadsUp(pickedChild);
mExpandingFromHeadsUp = true;
}
// otherwise we update the state when the expansion is finished
@@ -2696,4 +2709,8 @@ public class NotificationPanelView extends PanelView implements
}
}
}
+
+ public void addTrackingHeadsUpListener(Consumer listener) {
+ mTrackingHeadsUpListeners.add(listener);
+ }
}
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 7422a4343cb..4382e276d60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -189,6 +189,7 @@ import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
@@ -602,6 +603,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private NavigationBarFragment mNavigationBar;
private View mNavigationBarView;
protected ActivityLaunchAnimator mActivityLaunchAnimator;
+ private HeadsUpAppearanceController mHeadsUpAppearanceController;
@Override
public void start() {
@@ -807,6 +809,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mStatusBarView.setPanel(mNotificationPanel);
mStatusBarView.setScrimController(mScrimController);
mStatusBarView.setBouncerShowing(mBouncerShowing);
+ mHeadsUpAppearanceController = new HeadsUpAppearanceController(
+ mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);
setAreThereNotifications();
checkBarModes();
}).getFragmentManager()
@@ -1087,6 +1091,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mKeyguardUserSwitcher.onDensityOrFontScaleChanged();
}
mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
+ mHeadsUpManager.onDensityOrFontScaleChanged();
reevaluateStyles();
}
@@ -1991,7 +1996,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mVisualStabilityManager.setPanelExpanded(isExpanded);
if (isExpanded && getBarState() != StatusBarState.KEYGUARD) {
if (DEBUG) {
- Log.v(TAG, "clearing notification effects from setPanelExpanded");
+ Log.v(TAG, "clearing notification effects from setExpandedHeight");
}
clearNotificationEffects();
}
@@ -2813,7 +2818,7 @@ public class StatusBar extends SystemUI implements DemoMode,
public void setRemoteInputActive(NotificationData.Entry entry,
boolean remoteInputActive) {
mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
- entry.row.updateMaxHeights();
+ entry.row.notifyHeightChanged(true /* needsAnimation */);
}
public void lockScrollTo(NotificationData.Entry entry) {
mStackScroller.lockScrollTo(entry.row);
@@ -3833,6 +3838,9 @@ public class StatusBar extends SystemUI implements DemoMode,
if (mStackScroller == null) return;
boolean onKeyguard = mState == StatusBarState.KEYGUARD;
boolean publicMode = mLockscreenUserManager.isAnyProfilePublicMode();
+ if (mHeadsUpAppearanceController != null) {
+ mHeadsUpAppearanceController.setPublicMode(publicMode);
+ }
mStackScroller.setHideSensitive(publicMode, goingToFullShade);
mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
mStackScroller.setExpandingEnabled(!onKeyguard);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 040d7ec32ec..aeda55a8bf8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -443,6 +443,9 @@ public class HeadsUpManager {
entry.reset();
}
+ public void onDensityOrFontScaleChanged() {
+ }
+
/**
* This represents a notification and how long it is in a heads up mode. It also manages its
* lifecycle automatically when created.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index ac2a1e1e041..e5ab712e9bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -102,6 +102,9 @@ public class NotificationChildrenContainer extends ViewGroup {
private boolean mShowDividersWhenExpanded;
private boolean mHideDividersDuringExpand;
+ private int mTranslationForHeader;
+ private int mCurrentHeaderTranslation = 0;
+ private float mHeaderVisibleAmount = 1.0f;
public NotificationChildrenContainer(Context context) {
this(context, null);
@@ -142,6 +145,9 @@ public class NotificationChildrenContainer extends ViewGroup {
res.getBoolean(R.bool.config_showDividersWhenGroupNotificationExpanded);
mHideDividersDuringExpand =
res.getBoolean(R.bool.config_hideDividersDuringExpand);
+ mTranslationForHeader = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin)
+ - mNotificationHeaderMargin;
}
@Override
@@ -486,7 +492,7 @@ public class NotificationChildrenContainer extends ViewGroup {
if (showingAsLowPriority()) {
return mNotificationHeaderLowPriority.getHeight();
}
- int intrinsicHeight = mNotificationHeaderMargin;
+ int intrinsicHeight = mNotificationHeaderMargin + mCurrentHeaderTranslation;
int visibleChildren = 0;
int childCount = mChildren.size();
boolean firstChild = true;
@@ -541,7 +547,7 @@ public class NotificationChildrenContainer extends ViewGroup {
public void getState(StackScrollState resultState, ExpandableViewState parentState,
AmbientState ambientState) {
int childCount = mChildren.size();
- int yPosition = mNotificationHeaderMargin;
+ int yPosition = mNotificationHeaderMargin + mCurrentHeaderTranslation;
boolean firstChild = true;
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
int lastVisibleIndex = maxAllowedVisibleChildren - 1;
@@ -645,6 +651,11 @@ public class NotificationChildrenContainer extends ViewGroup {
mHeaderViewState.zTranslation = childrenExpandedAndNotAnimating
? parentState.zTranslation
: 0;
+ mHeaderViewState.yTranslation = mCurrentHeaderTranslation;
+ mHeaderViewState.alpha = mHeaderVisibleAmount;
+ // The hiding is done automatically by the alpha, otherwise we'll pick it up again
+ // in the next frame with the initFrom call above and have an invisible header
+ mHeaderViewState.hidden = false;
}
}
@@ -1009,7 +1020,8 @@ public class NotificationChildrenContainer extends ViewGroup {
return getMinHeight(NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED, true
/* likeHighPriority */);
}
- int maxContentHeight = mNotificationHeaderMargin + mNotificatonTopPadding;
+ int maxContentHeight = mNotificationHeaderMargin + mCurrentHeaderTranslation
+ + mNotificatonTopPadding;
int visibleChildren = 0;
int childCount = mChildren.size();
for (int i = 0; i < childCount; i++) {
@@ -1071,7 +1083,8 @@ public class NotificationChildrenContainer extends ViewGroup {
}
private int getVisibleChildrenExpandHeight() {
- int intrinsicHeight = mNotificationHeaderMargin + mNotificatonTopPadding + mDividerHeight;
+ int intrinsicHeight = mNotificationHeaderMargin + mCurrentHeaderTranslation
+ + mNotificatonTopPadding + mDividerHeight;
int visibleChildren = 0;
int childCount = mChildren.size();
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */);
@@ -1110,7 +1123,7 @@ public class NotificationChildrenContainer extends ViewGroup {
if (!likeHighPriority && showingAsLowPriority()) {
return mNotificationHeaderLowPriority.getHeight();
}
- int minExpandHeight = mNotificationHeaderMargin;
+ int minExpandHeight = mNotificationHeaderMargin + mCurrentHeaderTranslation;
int visibleChildren = 0;
boolean firstChild = true;
int childCount = mChildren.size();
@@ -1190,7 +1203,8 @@ public class NotificationChildrenContainer extends ViewGroup {
}
public int getPositionInLinearLayout(View childInGroup) {
- int position = mNotificationHeaderMargin + mNotificatonTopPadding;
+ int position = mNotificationHeaderMargin + mCurrentHeaderTranslation
+ + mNotificatonTopPadding;
for (int i = 0; i < mChildren.size(); i++) {
ExpandableNotificationRow child = mChildren.get(i);
@@ -1281,4 +1295,9 @@ public class NotificationChildrenContainer extends ViewGroup {
last = false;
}
}
+
+ public void setHeaderVisibleAmount(float headerVisibleAmount) {
+ mHeaderVisibleAmount = headerVisibleAmount;
+ mCurrentHeaderTranslation = (int) ((1.0f - headerVisibleAmount) * mTranslationForHeader);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationRoundnessManager.java
index 30997717f31..a36c966a331 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationRoundnessManager.java
@@ -20,7 +20,6 @@ import android.view.View;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import java.util.HashSet;
@@ -35,6 +34,8 @@ class NotificationRoundnessManager implements OnHeadsUpChangedListener {
private ActivatableNotificationView mLast;
private HashSet mAnimatedChildren;
private Runnable mRoundingChangedCallback;
+ private ExpandableNotificationRow mTrackedHeadsUp;
+ private float mAppearFraction;
@Override
public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
@@ -66,11 +67,20 @@ class NotificationRoundnessManager implements OnHeadsUpChangedListener {
if (view == mLast && !top) {
return 1.0f;
}
+ if (view == mTrackedHeadsUp && mAppearFraction <= 0.0f) {
+ // If we're pushing up on a headsup the appear fraction is < 0 and it needs to still be
+ // rounded.
+ return 1.0f;
+ }
return 0.0f;
}
- public void setExpanded(boolean expanded) {
- mExpanded = expanded;
+ public void setExpanded(float expandedHeight, float appearFraction) {
+ mExpanded = expandedHeight != 0.0f;
+ mAppearFraction = appearFraction;
+ if (mTrackedHeadsUp != null) {
+ updateRounding(mTrackedHeadsUp, true);
+ }
}
public void setFirstAndLastBackgroundChild(ActivatableNotificationView first,
@@ -106,4 +116,8 @@ class NotificationRoundnessManager implements OnHeadsUpChangedListener {
public void setOnRoundingChangedCallback(Runnable roundingChangedCallback) {
mRoundingChangedCallback = roundingChangedCallback;
}
+
+ public void setTrackingHeadsUp(ExpandableNotificationRow row) {
+ mTrackedHeadsUp = row;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index e4551674116..174e7347669 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -94,8 +94,8 @@ import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.ScrollAdapter;
@@ -108,6 +108,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
+import java.util.function.BiConsumer;
/**
* A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
@@ -404,6 +405,8 @@ public class NotificationStackScrollLayout extends ViewGroup
private final Rect mTmpRect = new Rect();
private int mClockBottom;
private int mAntiBurnInOffsetX;
+ private ArrayList> mExpandedHeightListeners = new ArrayList<>();
+ private int mHeadsUpInset;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -443,6 +446,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mDarkSeparatorPadding = res.getDimensionPixelSize(R.dimen.widget_bottom_separator_padding);
mRoundnessManager.setAnimatedChildren(mChildrenToAddAnimated);
mRoundnessManager.setOnRoundingChangedCallback(this::invalidate);
+ addOnExpandedHeightListener(mRoundnessManager::setExpanded);
updateWillNotDraw();
mBackgroundPaint.setAntiAlias(true);
@@ -585,13 +589,15 @@ public class NotificationStackScrollLayout extends ViewGroup
res.getDimensionPixelSize(R.dimen.notification_divider_height_increased);
mMinTopOverScrollToEscape = res.getDimensionPixelSize(
R.dimen.min_top_overscroll_to_qs);
- mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height);
+ mStatusBarHeight = res.getDimensionPixelSize(R.dimen.status_bar_height);
mBottomMargin = res.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom);
mSidePaddings = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
mMinInteractionHeight = res.getDimensionPixelSize(
R.dimen.notification_min_interaction_height);
mCornerRadius = res.getDimensionPixelSize(
Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
+ mHeadsUpInset = mStatusBarHeight + res.getDimensionPixelSize(
+ R.dimen.heads_up_status_bar_padding);
}
public void setDrawBackgroundAsSrc(boolean asSrc) {
@@ -704,7 +710,8 @@ public class NotificationStackScrollLayout extends ViewGroup
}
private void updateAlgorithmLayoutMinHeight() {
- mAmbientState.setLayoutMinHeight(mQsExpanded && !onKeyguard() ? getLayoutMinHeight() : 0);
+ mAmbientState.setLayoutMinHeight(mQsExpanded && !onKeyguard() || isHeadsUpTransition()
+ ? getLayoutMinHeight() : 0);
}
/**
@@ -857,11 +864,12 @@ public class NotificationStackScrollLayout extends ViewGroup
float translationY;
float appearEndPosition = getAppearEndPosition();
float appearStartPosition = getAppearStartPosition();
+ float appearFraction = 1.0f;
if (height >= appearEndPosition) {
translationY = 0;
stackHeight = (int) height;
} else {
- float appearFraction = getAppearFraction(height);
+ appearFraction = getAppearFraction(height);
if (appearFraction >= 0) {
translationY = NotificationUtils.interpolate(getExpandTranslationStart(), 0,
appearFraction);
@@ -870,7 +878,12 @@ public class NotificationStackScrollLayout extends ViewGroup
// start
translationY = height - appearStartPosition + getExpandTranslationStart();
}
- stackHeight = (int) (height - translationY);
+ if (isHeadsUpTransition()) {
+ stackHeight = mFirstVisibleBackgroundChild.getPinnedHeadsUpHeight();
+ translationY = MathUtils.lerp(mHeadsUpInset - mTopPadding, 0, appearFraction);
+ } else {
+ stackHeight = (int) (height - translationY);
+ }
}
if (stackHeight != mCurrentStackHeight) {
mCurrentStackHeight = stackHeight;
@@ -878,6 +891,10 @@ public class NotificationStackScrollLayout extends ViewGroup
requestChildrenUpdate();
}
setStackTranslation(translationY);
+ for (int i = 0; i < mExpandedHeightListeners.size(); i++) {
+ BiConsumer listener = mExpandedHeightListeners.get(i);
+ listener.accept(mExpandedHeight, appearFraction);
+ }
}
private void setRequestedClipBounds(Rect clipRect) {
@@ -912,12 +929,8 @@ public class NotificationStackScrollLayout extends ViewGroup
* Measured in absolute height.
*/
private float getAppearStartPosition() {
- if (mTrackingHeadsUp && mFirstVisibleBackgroundChild != null) {
- if (mAmbientState.isAboveShelf(mFirstVisibleBackgroundChild)) {
- // If we ever expanded beyond the first notification, it's allowed to merge into
- // the shelf
- return mFirstVisibleBackgroundChild.getPinnedHeadsUpHeight();
- }
+ if (isHeadsUpTransition()) {
+ return mHeadsUpInset + mFirstVisibleBackgroundChild.getPinnedHeadsUpHeight();
}
return getMinExpansionHeight();
}
@@ -951,17 +964,14 @@ public class NotificationStackScrollLayout extends ViewGroup
int appearPosition;
int notGoneChildCount = getNotGoneChildCount();
if (mEmptyShadeView.getVisibility() == GONE && notGoneChildCount != 0) {
- int minNotificationsForShelf = 1;
- if (mTrackingHeadsUp
+ if (isHeadsUpTransition()
|| (mHeadsUpManager.hasPinnedHeadsUp() && !mAmbientState.isDark())) {
appearPosition = getTopHeadsUpPinnedHeight();
- minNotificationsForShelf = 2;
} else {
appearPosition = 0;
- }
- if (notGoneChildCount >= minNotificationsForShelf
- && mShelf.getVisibility() != GONE) {
- appearPosition += mShelf.getIntrinsicHeight();
+ if (notGoneChildCount >= 1 && mShelf.getVisibility() != GONE) {
+ appearPosition += mShelf.getIntrinsicHeight();
+ }
}
} else {
appearPosition = mEmptyShadeView.getHeight();
@@ -969,6 +979,11 @@ public class NotificationStackScrollLayout extends ViewGroup
return appearPosition + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
}
+ private boolean isHeadsUpTransition() {
+ return mTrackingHeadsUp && mFirstVisibleBackgroundChild != null
+ && mAmbientState.isAboveShelf(mFirstVisibleBackgroundChild);
+ }
+
/**
* @param height the height of the panel
* @return the fraction of the appear animation that has been performed
@@ -2524,6 +2539,9 @@ public class NotificationStackScrollLayout extends ViewGroup
}
public int getLayoutMinHeight() {
+ if (isHeadsUpTransition()) {
+ return getTopHeadsUpPinnedHeight();
+ }
return mShelf.getVisibility() == GONE ? 0 : mShelf.getIntrinsicHeight();
}
@@ -3551,7 +3569,6 @@ public class NotificationStackScrollLayout extends ViewGroup
private void setIsExpanded(boolean isExpanded) {
boolean changed = isExpanded != mIsExpanded;
mIsExpanded = isExpanded;
- mRoundnessManager.setExpanded(isExpanded);
mStackScrollAlgorithm.setIsExpanded(isExpanded);
if (changed) {
if (!mIsExpanded) {
@@ -4300,8 +4317,9 @@ public class NotificationStackScrollLayout extends ViewGroup
requestChildrenUpdate();
}
- public void setTrackingHeadsUp(boolean trackingHeadsUp) {
- mTrackingHeadsUp = trackingHeadsUp;
+ public void setTrackingHeadsUp(ExpandableNotificationRow row) {
+ mTrackingHeadsUp = row != null;
+ mRoundnessManager.setTrackingHeadsUp(row);
}
public void setScrimController(ScrimController scrimController) {
@@ -4483,6 +4501,16 @@ public class NotificationStackScrollLayout extends ViewGroup
mAmbientState.getScrollY()));
}
+ /**
+ * Add a listener whenever the expanded height changes. The first value passed as an argument
+ * is the expanded height and the second one is the appearFraction.
+ *
+ * @param listener the listener to notify.
+ */
+ public void addOnExpandedHeightListener(BiConsumer listener) {
+ mExpandedHeightListeners.add(listener);
+ }
+
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 51737a86374..bf6af22a0cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -50,6 +50,7 @@ public class StackScrollAlgorithm {
private boolean mIsExpanded;
private boolean mClipNotificationScrollToTop;
private int mStatusBarHeight;
+ private float mHeadsUpInset;
public StackScrollAlgorithm(Context context) {
initView(context);
@@ -68,6 +69,8 @@ public class StackScrollAlgorithm {
mCollapsedSize = res.getDimensionPixelSize(R.dimen.notification_min_height);
mStatusBarHeight = res.getDimensionPixelSize(R.dimen.status_bar_height);
mClipNotificationScrollToTop = res.getBoolean(R.bool.config_clipNotificationScrollToTop);
+ mHeadsUpInset = mStatusBarHeight + res.getDimensionPixelSize(
+ R.dimen.heads_up_status_bar_padding);
}
public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) {
@@ -457,7 +460,7 @@ public class StackScrollAlgorithm {
}
}
if (row.isPinned()) {
- childState.yTranslation = Math.max(childState.yTranslation, 0);
+ childState.yTranslation = Math.max(childState.yTranslation, mHeadsUpInset);
childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
childState.hidden = false;
ExpandableViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
new file mode 100644
index 00000000000..c904ef30dd1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.TestableDependency;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.HeadsUpStatusBarView;
+import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
+
+ private HeadsUpAppearanceController mHeadsUpAppearanceController;
+ private ExpandableNotificationRow mFirst;
+ private HeadsUpStatusBarView mHeadsUpStatusBarView;
+ private HeadsUpManagerPhone mHeadsUpManager;
+
+ @Before
+ public void setUp() throws Exception {
+ NotificationTestHelper testHelper = new NotificationTestHelper(getContext());
+ mFirst = testHelper.createRow();
+ mDependency.injectMockDependency(DarkIconDispatcher.class);
+ mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
+ mock(TextView.class));
+ mHeadsUpManager = mock(HeadsUpManagerPhone.class);
+ mHeadsUpAppearanceController = new HeadsUpAppearanceController(
+ mock(NotificationIconAreaController.class),
+ mHeadsUpManager,
+ mHeadsUpStatusBarView,
+ mock(NotificationStackScrollLayout.class),
+ mock(NotificationPanelView.class),
+ new View(mContext));
+ mHeadsUpAppearanceController.setExpandedHeight(0.0f, 0.0f);
+ }
+
+ @Test
+ public void testShowinEntryUpdated() {
+ mFirst.setPinned(true);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
+ when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
+ mHeadsUpAppearanceController.onHeadsUpPinned(mFirst);
+ Assert.assertEquals(mFirst.getEntry(), mHeadsUpStatusBarView.getShowingEntry());
+
+ mFirst.setPinned(false);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
+ mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst);
+ Assert.assertEquals(null, mHeadsUpStatusBarView.getShowingEntry());
+ }
+
+ @Test
+ public void testShownUpdated() {
+ mFirst.setPinned(true);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
+ when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
+ mHeadsUpAppearanceController.onHeadsUpPinned(mFirst);
+ Assert.assertTrue(mHeadsUpAppearanceController.isShown());
+
+ mFirst.setPinned(false);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
+ mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst);
+ Assert.assertFalse(mHeadsUpAppearanceController.isShown());
+ }
+
+ @Test
+ public void testHeaderUpdated() {
+ mFirst.setPinned(true);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
+ when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
+ mHeadsUpAppearanceController.onHeadsUpPinned(mFirst);
+ Assert.assertEquals(mFirst.getHeaderVisibleAmount(), 0.0f, 0.0f);
+
+ mFirst.setPinned(false);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
+ mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst);
+ Assert.assertEquals(mFirst.getHeaderVisibleAmount(), 1.0f, 0.0f);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationRoundnessManagerTest.java
index ea754c71cad..1d2c01dbd56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationRoundnessManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationRoundnessManagerTest.java
@@ -65,7 +65,7 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
mRoundnessManager.setOnRoundingChangedCallback(mRoundnessCallback);
mRoundnessManager.setAnimatedChildren(mAnimatedChildren);
mRoundnessManager.setFirstAndLastBackgroundChild(mFirst, mFirst);
- mRoundnessManager.setExpanded(true);
+ mRoundnessManager.setExpanded(1.0f, 1.0f);
}
@Test
@@ -112,7 +112,7 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
@Test
public void testRoundedWhenPinnedAndCollapsed() {
mFirst.setPinned(true);
- mRoundnessManager.setExpanded(false);
+ mRoundnessManager.setExpanded(0.0f /* expandedHeight */, 0.0f /* appearFraction */);
mRoundnessManager.setFirstAndLastBackgroundChild(mSecond, mSecond);
Assert.assertEquals(1.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
Assert.assertEquals(1.0f, mFirst.getCurrentTopRoundness(), 0.0f);
@@ -121,7 +121,7 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
@Test
public void testRoundedWhenGoingAwayAndCollapsed() {
mFirst.setHeadsUpAnimatingAway(true);
- mRoundnessManager.setExpanded(false);
+ mRoundnessManager.setExpanded(0.0f /* expandedHeight */, 0.0f /* appearFraction */);
mRoundnessManager.setFirstAndLastBackgroundChild(mSecond, mSecond);
Assert.assertEquals(1.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
Assert.assertEquals(1.0f, mFirst.getCurrentTopRoundness(), 0.0f);
@@ -130,7 +130,25 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
@Test
public void testRoundedNormalRoundingWhenExpanded() {
mFirst.setHeadsUpAnimatingAway(true);
- mRoundnessManager.setExpanded(true);
+ mRoundnessManager.setExpanded(1.0f /* expandedHeight */, 0.0f /* appearFraction */);
+ mRoundnessManager.setFirstAndLastBackgroundChild(mSecond, mSecond);
+ Assert.assertEquals(0.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
+ Assert.assertEquals(0.0f, mFirst.getCurrentTopRoundness(), 0.0f);
+ }
+
+ @Test
+ public void testTrackingHeadsUpRoundedIfPushingUp() {
+ mRoundnessManager.setExpanded(1.0f /* expandedHeight */, -0.5f /* appearFraction */);
+ mRoundnessManager.setTrackingHeadsUp(mFirst);
+ mRoundnessManager.setFirstAndLastBackgroundChild(mSecond, mSecond);
+ Assert.assertEquals(1.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
+ Assert.assertEquals(1.0f, mFirst.getCurrentTopRoundness(), 0.0f);
+ }
+
+ @Test
+ public void testTrackingHeadsUpNotRoundedIfPushingDown() {
+ mRoundnessManager.setExpanded(1.0f /* expandedHeight */, 0.5f /* appearFraction */);
+ mRoundnessManager.setTrackingHeadsUp(mFirst);
mRoundnessManager.setFirstAndLastBackgroundChild(mSecond, mSecond);
Assert.assertEquals(0.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
Assert.assertEquals(0.0f, mFirst.getCurrentTopRoundness(), 0.0f);
--
GitLab
From 99e9adf51924870f28142813c5667c8e67b2298b Mon Sep 17 00:00:00 2001
From: Selim Cinek
Date: Thu, 15 Mar 2018 09:17:47 -0700
Subject: [PATCH 476/488] Removed the heads up scrim and replaced it with more
elevation
Fixes: 72748440
Test: runtest systemui
Change-Id: Id1eb413a2a44589727d212c0fefe3a1b742bb25e
---
.../SystemUI/res/drawable/heads_up_scrim.xml | 25 ------
.../SystemUI/res/layout/super_status_bar.xml | 8 --
packages/SystemUI/res/values/dimens.xml | 4 +-
.../com/android/systemui/SystemUIFactory.java | 8 +-
.../statusbar/ExpandableNotificationRow.java | 2 +-
.../systemui/statusbar/ExpandableView.java | 4 +
.../statusbar/phone/ScrimController.java | 89 +------------------
.../systemui/statusbar/phone/StatusBar.java | 5 +-
.../stack/NotificationStackScrollLayout.java | 4 -
.../statusbar/stack/StackScrollAlgorithm.java | 10 +++
.../statusbar/phone/ScrimControllerTest.java | 59 +-----------
11 files changed, 29 insertions(+), 189 deletions(-)
delete mode 100644 packages/SystemUI/res/drawable/heads_up_scrim.xml
diff --git a/packages/SystemUI/res/drawable/heads_up_scrim.xml b/packages/SystemUI/res/drawable/heads_up_scrim.xml
deleted file mode 100644
index 59000fcf37d..00000000000
--- a/packages/SystemUI/res/drawable/heads_up_scrim.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index ef442e539c0..75403b91d29 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -51,14 +51,6 @@
sysui:ignoreRightInset="true"
/>
-
-
8dp
+
+ 16dp
+
196dp
@@ -454,7 +457,6 @@
30dp36dp
- 250dp0.62
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 91edfda0626..391843ce55b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -100,10 +100,10 @@ public class SystemUIFactory {
}
public ScrimController createScrimController(LightBarController lightBarController,
- ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim,
- LockscreenWallpaper lockscreenWallpaper, Consumer scrimVisibleListener,
- DozeParameters dozeParameters, AlarmManager alarmManager) {
- return new ScrimController(lightBarController, scrimBehind, scrimInFront, headsUpScrim,
+ ScrimView scrimBehind, ScrimView scrimInFront, LockscreenWallpaper lockscreenWallpaper,
+ Consumer scrimVisibleListener, DozeParameters dozeParameters,
+ AlarmManager alarmManager) {
+ return new ScrimController(lightBarController, scrimBehind, scrimInFront,
scrimVisibleListener, dozeParameters, alarmManager);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 4001f9e04a7..e445ba100a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -552,7 +552,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
- @VisibleForTesting
+ @Override
public float getHeaderVisibleAmount() {
return mHeaderVisibleAmount;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 204adc813f5..827866fdc0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -390,6 +390,10 @@ public abstract class ExpandableView extends FrameLayout {
}
}
+ public float getHeaderVisibleAmount() {
+ return 1.0f;
+ }
+
protected boolean shouldClipToActualHeight() {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 739d8d5c2c6..f8ae7f76105 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -49,7 +49,6 @@ import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.stack.ViewState;
import com.android.systemui.util.AlarmTimeout;
import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -63,8 +62,8 @@ import java.util.function.Consumer;
* Controls both the scrim behind the notifications and in front of the notifications (when a
* security method gets shown).
*/
-public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
- OnHeadsUpChangedListener, OnColorsChangedListener, Dumpable {
+public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnColorsChangedListener,
+ Dumpable {
private static final String TAG = "ScrimController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -106,7 +105,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
private final Context mContext;
protected final ScrimView mScrimBehind;
protected final ScrimView mScrimInFront;
- private final View mHeadsUpScrim;
private final LightBarController mLightBarController;
private final UnlockMethodCache mUnlockMethodCache;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -140,9 +138,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
private int mCurrentInFrontTint;
private int mCurrentBehindTint;
private boolean mWallpaperVisibilityTimedOut;
- private int mPinnedHeadsUpCount;
- private float mTopHeadsUpDragAmount;
- private View mDraggedHeadsUpView;
private int mScrimsVisibility;
private final Consumer mScrimVisibleListener;
private boolean mBlankScreen;
@@ -161,11 +156,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
private boolean mKeyguardOccluded;
public ScrimController(LightBarController lightBarController, ScrimView scrimBehind,
- ScrimView scrimInFront, View headsUpScrim, Consumer scrimVisibleListener,
+ ScrimView scrimInFront, Consumer scrimVisibleListener,
DozeParameters dozeParameters, AlarmManager alarmManager) {
mScrimBehind = scrimBehind;
mScrimInFront = scrimInFront;
- mHeadsUpScrim = headsUpScrim;
mScrimVisibleListener = scrimVisibleListener;
mContext = scrimBehind.getContext();
mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
@@ -196,7 +190,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
}
mState = ScrimState.UNINITIALIZED;
- updateHeadsUpScrim(false);
updateScrims();
}
@@ -363,10 +356,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
return;
}
- if (mPinnedHeadsUpCount != 0) {
- updateHeadsUpScrim(false);
- }
-
setOrAdaptCurrentAnimation(mScrimBehind);
setOrAdaptCurrentAnimation(mScrimInFront);
}
@@ -610,8 +599,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
return mCurrentInFrontAlpha;
} else if (scrim == mScrimBehind) {
return mCurrentBehindAlpha;
- } else if (scrim == mHeadsUpScrim) {
- return calculateHeadsUpAlpha();
} else {
throw new IllegalArgumentException("Unknown scrim view");
}
@@ -622,8 +609,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
return mCurrentInFrontTint;
} else if (scrim == mScrimBehind) {
return mCurrentBehindTint;
- } else if (scrim == mHeadsUpScrim) {
- return Color.TRANSPARENT;
} else {
throw new IllegalArgumentException("Unknown scrim view");
}
@@ -670,40 +655,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
mScrimBehind.setDrawAsSrc(asSrc);
}
- @Override
- public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
- }
-
- @Override
- public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
- mPinnedHeadsUpCount++;
- updateHeadsUpScrim(true);
- }
-
- @Override
- public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
- mPinnedHeadsUpCount--;
- if (headsUp == mDraggedHeadsUpView) {
- mDraggedHeadsUpView = null;
- mTopHeadsUpDragAmount = 0.0f;
- }
- updateHeadsUpScrim(true);
- }
-
- @Override
- public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
- }
-
- private void updateHeadsUpScrim(boolean animate) {
- if (animate) {
- mAnimationDuration = ANIMATION_DURATION;
- cancelAnimator((ValueAnimator) mHeadsUpScrim.getTag(TAG_KEY_ANIM));
- startScrimAnimation(mHeadsUpScrim, mHeadsUpScrim.getAlpha());
- } else {
- setOrAdaptCurrentAnimation(mHeadsUpScrim);
- }
- }
-
@VisibleForTesting
void setOnAnimationFinished(Runnable onAnimationFinished) {
mOnAnimationFinished = onAnimationFinished;
@@ -810,33 +761,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
return Handler.getMain();
}
- /**
- * Set the amount the current top heads up view is dragged. The range is from 0 to 1 and 0 means
- * the heads up is in its resting space and 1 means it's fully dragged out.
- *
- * @param draggedHeadsUpView the dragged view
- * @param topHeadsUpDragAmount how far is it dragged
- */
- public void setTopHeadsUpDragAmount(View draggedHeadsUpView, float topHeadsUpDragAmount) {
- mTopHeadsUpDragAmount = topHeadsUpDragAmount;
- mDraggedHeadsUpView = draggedHeadsUpView;
- updateHeadsUpScrim(false);
- }
-
- private float calculateHeadsUpAlpha() {
- float alpha;
- if (mPinnedHeadsUpCount >= 2) {
- alpha = 1.0f;
- } else if (mPinnedHeadsUpCount == 0) {
- alpha = 0.0f;
- } else {
- alpha = 1.0f - mTopHeadsUpDragAmount;
- }
- float expandFactor = (1.0f - mExpansionFraction);
- expandFactor = Math.max(expandFactor, 0.0f);
- return alpha * expandFactor;
- }
-
public void setExcludedBackgroundArea(Rect area) {
mScrimBehind.setExcludedArea(area);
}
@@ -851,13 +775,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
mScrimBehind.setChangeRunnable(changeRunnable);
}
- public void onDensityOrFontScaleChanged() {
- ViewGroup.LayoutParams layoutParams = mHeadsUpScrim.getLayoutParams();
- layoutParams.height = mHeadsUpScrim.getResources().getDimensionPixelSize(
- R.dimen.heads_up_scrim_height);
- mHeadsUpScrim.setLayoutParams(layoutParams);
- }
-
public void setCurrentUser(int currentUser) {
// Don't care in the base class.
}
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 4382e276d60..870dbaf977f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -903,9 +903,8 @@ public class StatusBar extends SystemUI implements DemoMode,
ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind);
ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front);
- View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
mScrimController = SystemUIFactory.getInstance().createScrimController(mLightBarController,
- scrimBehind, scrimInFront, headsUpScrim, mLockscreenWallpaper,
+ scrimBehind, scrimInFront, mLockscreenWallpaper,
scrimsVisible -> {
if (mStatusBarWindowManager != null) {
mStatusBarWindowManager.setScrimsVisibility(scrimsVisible);
@@ -920,7 +919,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mBackdrop.setOnVisibilityChangedRunnable(runnable);
runnable.run();
}
- mHeadsUpManager.addListener(mScrimController);
mStackScroller.setScrimController(mScrimController);
mDozeScrimController = new DozeScrimController(mScrimController, context);
@@ -1077,7 +1075,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mReinflateNotificationsOnUserSwitched = true;
}
// end old BaseStatusBar.onDensityOrFontScaleChanged().
- mScrimController.onDensityOrFontScaleChanged();
// TODO: Remove this.
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.onDensityOrFontScaleChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 174e7347669..dd07830b040 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1094,10 +1094,6 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
- if (!mIsExpanded && isPinnedHeadsUp(animView) && canChildBeDismissed(animView)) {
- mScrimController.setTopHeadsUpDragAmount(animView,
- Math.min(Math.abs(swipeProgress / 2f - 1.0f), 1.0f));
- }
// Returning true prevents alpha fading.
return !mFadeNotificationsOnDismiss;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index bf6af22a0cc..ff14238f3f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -51,6 +51,7 @@ public class StackScrollAlgorithm {
private boolean mClipNotificationScrollToTop;
private int mStatusBarHeight;
private float mHeadsUpInset;
+ private int mPinnedZTranslationExtra;
public StackScrollAlgorithm(Context context) {
initView(context);
@@ -71,6 +72,8 @@ public class StackScrollAlgorithm {
mClipNotificationScrollToTop = res.getBoolean(R.bool.config_clipNotificationScrollToTop);
mHeadsUpInset = mStatusBarHeight + res.getDimensionPixelSize(
R.dimen.heads_up_status_bar_padding);
+ mPinnedZTranslationExtra = res.getDimensionPixelSize(
+ R.dimen.heads_up_pinned_elevation);
}
public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) {
@@ -595,6 +598,13 @@ public class StackScrollAlgorithm {
} else {
childViewState.zTranslation = baseZ;
}
+
+ // We need to scrim the notification more from its surrounding content when we are pinned,
+ // and we therefore elevate it higher.
+ // We can use the headerVisibleAmount for this, since the value nicely goes from 0 to 1 when
+ // expanding after which we have a normal elevation again.
+ childViewState.zTranslation += (1.0f - child.getHeaderVisibleAmount())
+ * mPinnedZTranslationExtra;
return childrenOnTop;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index d32c9a8e564..72d9cc83627 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -64,7 +64,6 @@ public class ScrimControllerTest extends SysuiTestCase {
private SynchronousScrimController mScrimController;
private ScrimView mScrimBehind;
private ScrimView mScrimInFront;
- private View mHeadsUpScrim;
private Consumer mScrimVisibilityCallback;
private int mScrimVisibility;
private LightBarController mLightBarController;
@@ -78,7 +77,6 @@ public class ScrimControllerTest extends SysuiTestCase {
mLightBarController = mock(LightBarController.class);
mScrimBehind = new ScrimView(getContext());
mScrimInFront = new ScrimView(getContext());
- mHeadsUpScrim = new View(getContext());
mWakeLock = mock(WakeLock.class);
mAlarmManager = mock(AlarmManager.class);
mAlwaysOnEnabled = true;
@@ -87,7 +85,7 @@ public class ScrimControllerTest extends SysuiTestCase {
when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
when(mDozeParamenters.getDisplayNeedsBlanking()).thenReturn(true);
mScrimController = new SynchronousScrimController(mLightBarController, mScrimBehind,
- mScrimInFront, mHeadsUpScrim, mScrimVisibilityCallback, mDozeParamenters,
+ mScrimInFront, mScrimVisibilityCallback, mDozeParamenters,
mAlarmManager);
}
@@ -414,56 +412,6 @@ public class ScrimControllerTest extends SysuiTestCase {
testConservesNotificationDensity(3 /* count */, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY);
}
- @Test
- public void testHeadsUpScrimOpacity() {
- mScrimController.setPanelExpansion(0f);
- mScrimController.onHeadsUpPinned(null /* row */);
- mScrimController.finishAnimationsImmediately();
-
- Assert.assertNotEquals("Heads-up scrim should be visible", 0f,
- mHeadsUpScrim.getAlpha(), 0.01f);
-
- mScrimController.onHeadsUpUnPinned(null /* row */);
- mScrimController.finishAnimationsImmediately();
-
- Assert.assertEquals("Heads-up scrim should have disappeared", 0f,
- mHeadsUpScrim.getAlpha(), 0.01f);
- }
-
- @Test
- public void testHeadsUpScrimCounting() {
- mScrimController.setPanelExpansion(0f);
- mScrimController.onHeadsUpPinned(null /* row */);
- mScrimController.onHeadsUpPinned(null /* row */);
- mScrimController.onHeadsUpPinned(null /* row */);
- mScrimController.finishAnimationsImmediately();
-
- Assert.assertNotEquals("Heads-up scrim should be visible", 0f,
- mHeadsUpScrim.getAlpha(), 0.01f);
-
- mScrimController.onHeadsUpUnPinned(null /* row */);
- mScrimController.finishAnimationsImmediately();
-
- Assert.assertEquals("Heads-up scrim should only disappear when counter reaches 0", 1f,
- mHeadsUpScrim.getAlpha(), 0.01f);
-
- mScrimController.onHeadsUpUnPinned(null /* row */);
- mScrimController.onHeadsUpUnPinned(null /* row */);
- mScrimController.finishAnimationsImmediately();
- Assert.assertEquals("Heads-up scrim should have disappeared", 0f,
- mHeadsUpScrim.getAlpha(), 0.01f);
- }
-
- @Test
- public void testNoHeadsUpScrimExpanded() {
- mScrimController.setPanelExpansion(1f);
- mScrimController.onHeadsUpPinned(null /* row */);
- mScrimController.finishAnimationsImmediately();
-
- Assert.assertEquals("Heads-up scrim should not be visible when shade is expanded", 0f,
- mHeadsUpScrim.getAlpha(), 0.01f);
- }
-
@Test
public void testScrimFocus() {
mScrimController.transitionTo(ScrimState.AOD);
@@ -542,10 +490,10 @@ public class ScrimControllerTest extends SysuiTestCase {
private boolean mAnimationCancelled;
SynchronousScrimController(LightBarController lightBarController,
- ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim,
+ ScrimView scrimBehind, ScrimView scrimInFront,
Consumer scrimVisibleListener, DozeParameters dozeParameters,
AlarmManager alarmManager) {
- super(lightBarController, scrimBehind, scrimInFront, headsUpScrim,
+ super(lightBarController, scrimBehind, scrimInFront,
scrimVisibleListener, dozeParameters, alarmManager);
mHandler = new FakeHandler(Looper.myLooper());
}
@@ -562,7 +510,6 @@ public class ScrimControllerTest extends SysuiTestCase {
// Force finish all animations.
endAnimation(mScrimBehind, TAG_KEY_ANIM);
endAnimation(mScrimInFront, TAG_KEY_ANIM);
- endAnimation(mHeadsUpScrim, TAG_KEY_ANIM);
if (!animationFinished[0]) {
throw new IllegalStateException("Animation never finished");
--
GitLab
From d03518cad57f9c8d664d3297c7bc840b172d4114 Mon Sep 17 00:00:00 2001
From: Selim Cinek
Date: Thu, 15 Mar 2018 12:13:51 -0700
Subject: [PATCH 477/488] Polished the heads up experience
Test: runtest systemui
Fixes: 72748440
Change-Id: I7025119675ed260b5fe53593ea3764918593cc5e
---
.../systemui/statusbar/CrossFadeHelper.java | 15 +++++-
.../statusbar/ExpandableNotificationRow.java | 7 +--
.../systemui/statusbar/StatusBarIconView.java | 40 +++++++++++++--
.../phone/HeadsUpAppearanceController.java | 33 ++++++++-----
.../phone/NotificationIconAreaController.java | 49 ++++++++++++-------
.../phone/NotificationIconContainer.java | 48 +++++++++++++++++-
.../systemui/statusbar/phone/StatusBar.java | 3 +-
7 files changed, 153 insertions(+), 42 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index e8f0925dcc7..4728a1d17b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -28,11 +28,17 @@ public class CrossFadeHelper {
public static final long ANIMATION_DURATION_LENGTH = 210;
public static void fadeOut(final View view, final Runnable endRunnable) {
+ fadeOut(view, ANIMATION_DURATION_LENGTH, 0, endRunnable);
+ }
+
+ public static void fadeOut(final View view, long duration, int delay,
+ final Runnable endRunnable) {
view.animate().cancel();
view.animate()
.alpha(0f)
- .setDuration(ANIMATION_DURATION_LENGTH)
+ .setDuration(duration)
.setInterpolator(Interpolators.ALPHA_OUT)
+ .setStartDelay(delay)
.withEndAction(new Runnable() {
@Override
public void run() {
@@ -93,6 +99,10 @@ public class CrossFadeHelper {
}
public static void fadeIn(final View view) {
+ fadeIn(view, ANIMATION_DURATION_LENGTH, 0);
+ }
+
+ public static void fadeIn(final View view, long duration, int delay) {
view.animate().cancel();
if (view.getVisibility() == View.INVISIBLE) {
view.setAlpha(0.0f);
@@ -100,7 +110,8 @@ public class CrossFadeHelper {
}
view.animate()
.alpha(1f)
- .setDuration(ANIMATION_DURATION_LENGTH)
+ .setDuration(duration)
+ .setStartDelay(delay)
.setInterpolator(Interpolators.ALPHA_IN)
.withEndAction(null);
if (view.hasOverlappingRendering()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index e445ba100a3..9bd8080525a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1058,11 +1058,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
- public void setDismissed(boolean dismissed, boolean fromAccessibility) {
- mDismissed = dismissed;
+ public void setDismissed(boolean fromAccessibility) {
+ mDismissed = true;
mGroupParentWhenDismissed = mNotificationParent;
mRefocusOnDismiss = fromAccessibility;
mChildAfterViewWhenDismissed = null;
+ mEntry.icon.setDismissed();
if (isChildInGroup()) {
List notificationChildren =
mNotificationParent.getNotificationChildren();
@@ -1146,7 +1147,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
groupSummary.performDismiss(fromAccessibility);
}
}
- setDismissed(true, fromAccessibility);
+ setDismissed(fromAccessibility);
if (isClearable()) {
if (mOnDismissRunnable != null) {
mOnDismissRunnable.run();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 6cfd42fa00e..5bb85e231f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -27,7 +27,6 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
@@ -43,7 +42,6 @@ import android.util.FloatProperty;
import android.util.Log;
import android.util.Property;
import android.util.TypedValue;
-import android.view.View;
import android.view.ViewDebug;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.Interpolator;
@@ -144,6 +142,8 @@ public class StatusBarIconView extends AnimatedImageView {
private ColorMatrixColorFilter mMatrixColorFilter;
private boolean mIsInShelf;
private Runnable mLayoutRunnable;
+ private boolean mDismissed;
+ private Runnable mOnDismissListener;
public StatusBarIconView(Context context, String slot, StatusBarNotification sbn) {
this(context, slot, sbn, false);
@@ -668,6 +668,19 @@ public class StatusBarIconView extends AnimatedImageView {
}
public void setVisibleState(int visibleState, boolean animate, Runnable endRunnable) {
+ setVisibleState(visibleState, animate, endRunnable, 0);
+ }
+
+ /**
+ * Set the visibleState of this view.
+ *
+ * @param visibleState The new state.
+ * @param animate Should we animate?
+ * @param endRunnable The runnable to run at the end.
+ * @param duration The duration of an animation or 0 if the default should be taken.
+ */
+ public void setVisibleState(int visibleState, boolean animate, Runnable endRunnable,
+ long duration) {
boolean runnableAdded = false;
if (visibleState != mVisibleState) {
mVisibleState = visibleState;
@@ -689,7 +702,8 @@ public class StatusBarIconView extends AnimatedImageView {
mIconAppearAnimator = ObjectAnimator.ofFloat(this, ICON_APPEAR_AMOUNT,
currentAmount, targetAmount);
mIconAppearAnimator.setInterpolator(interpolator);
- mIconAppearAnimator.setDuration(ANIMATION_DURATION_FAST);
+ mIconAppearAnimator.setDuration(duration == 0 ? ANIMATION_DURATION_FAST
+ : duration);
mIconAppearAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -711,8 +725,9 @@ public class StatusBarIconView extends AnimatedImageView {
if (targetAmount != currentAmount) {
mDotAnimator = ObjectAnimator.ofFloat(this, DOT_APPEAR_AMOUNT,
currentAmount, targetAmount);
- mDotAnimator.setInterpolator(interpolator);
- mDotAnimator.setDuration(ANIMATION_DURATION_FAST);
+ mDotAnimator.setInterpolator(interpolator);;
+ mDotAnimator.setDuration(duration == 0 ? ANIMATION_DURATION_FAST
+ : duration);
final boolean runRunnable = !runnableAdded;
mDotAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -837,6 +852,21 @@ public class StatusBarIconView extends AnimatedImageView {
mLayoutRunnable = runnable;
}
+ public void setDismissed() {
+ mDismissed = true;
+ if (mOnDismissListener != null) {
+ mOnDismissListener.run();
+ }
+ }
+
+ public boolean isDismissed() {
+ return mDismissed;
+ }
+
+ public void setOnDismissListener(Runnable onDismissListener) {
+ mOnDismissListener = onDismissListener;
+ }
+
public interface OnVisibilityChangedListener {
void onVisibilityChanged(int newVisibility);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index cd97c05ede2..7df6ae4ec50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -16,17 +16,13 @@
package com.android.systemui.statusbar.phone;
-import android.app.Notification;
-import android.app.PendingIntent;
import android.graphics.Rect;
-import android.service.notification.StatusBarNotification;
-import android.util.EventLog;
-import android.util.Log;
import android.view.View;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.NotificationData;
@@ -34,13 +30,13 @@ import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
-import java.util.stream.Stream;
-
/**
* Controls the appearance of heads up notifications in the icon area and the header itself.
*/
class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
DarkIconDispatcher.DarkReceiver {
+ public static final int CONTENT_FADE_DURATION = 110;
+ public static final int CONTENT_FADE_DELAY = 100;
private final NotificationIconAreaController mNotificationIconAreaController;
private final HeadsUpManagerPhone mHeadsUpManager;
private final NotificationStackScrollLayout mStackScroller;
@@ -98,24 +94,39 @@ class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
NotificationData.Entry previousEntry = mHeadsUpStatusBarView.getShowingEntry();
mHeadsUpStatusBarView.setEntry(newEntry);
if (newEntry != previousEntry) {
+ boolean animateIsolation = false;
if (newEntry == null) {
// no heads up anymore, lets start the disappear animation
setShown(false);
+ animateIsolation = !mIsExpanded;
} else if (previousEntry == null) {
// We now have a headsUp and didn't have one before. Let's start the disappear
// animation
setShown(true);
}
mNotificationIconAreaController.showIconIsolated(newEntry == null ? null
- : newEntry.icon, mHeadsUpStatusBarView.getIconDrawingRect());
+ : newEntry.icon, mHeadsUpStatusBarView.getIconDrawingRect(), animateIsolation);
}
}
private void setShown(boolean isShown) {
- mShown = isShown;
- mHeadsUpStatusBarView.setVisibility(isShown ? View.VISIBLE : View.GONE);
- mClockView.setVisibility(!isShown ? View.VISIBLE : View.INVISIBLE);
+ if (mShown != isShown) {
+ mShown = isShown;
+ if (isShown) {
+ mHeadsUpStatusBarView.setVisibility(View.VISIBLE);
+ CrossFadeHelper.fadeIn(mHeadsUpStatusBarView, CONTENT_FADE_DURATION /* duration */,
+ CONTENT_FADE_DELAY /* delay */);
+ CrossFadeHelper.fadeOut(mClockView, CONTENT_FADE_DURATION/* duration */,
+ 0 /* delay */, () -> mClockView.setVisibility(View.INVISIBLE));
+ } else {
+ CrossFadeHelper.fadeIn(mClockView, CONTENT_FADE_DURATION /* duration */,
+ CONTENT_FADE_DELAY /* delay */);
+ CrossFadeHelper.fadeOut(mHeadsUpStatusBarView, CONTENT_FADE_DURATION/* duration */,
+ 0 /* delay */, () -> mHeadsUpStatusBarView.setVisibility(View.GONE));
+
+ }
+ }
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 51adebfd05c..8acdad84c00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -12,9 +12,11 @@ import android.widget.FrameLayout;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.NotificationEntryManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -31,6 +33,8 @@ import java.util.function.Function;
*/
public class NotificationIconAreaController implements DarkReceiver {
private final NotificationColorUtil mNotificationColorUtil;
+ private final NotificationEntryManager mEntryManager;
+ private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
private int mIconSize;
private int mIconHPadding;
@@ -48,6 +52,7 @@ public class NotificationIconAreaController implements DarkReceiver {
mStatusBar = statusBar;
mNotificationColorUtil = NotificationColorUtil.getInstance(context);
mContext = context;
+ mEntryManager = Dependency.get(NotificationEntryManager.class);
initializeNotificationAreaViews(context);
}
@@ -129,8 +134,8 @@ public class NotificationIconAreaController implements DarkReceiver {
}
protected boolean shouldShowNotificationIcon(NotificationData.Entry entry,
- NotificationData notificationData, boolean showAmbient) {
- if (notificationData.isAmbient(entry.key) && !showAmbient) {
+ boolean showAmbient, boolean hideDismissed) {
+ if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
return false;
}
if (!StatusBar.isTopLevelChild(entry)) {
@@ -139,9 +144,13 @@ public class NotificationIconAreaController implements DarkReceiver {
if (entry.row.getVisibility() == View.GONE) {
return false;
}
+ if (entry.row.isDismissed() && hideDismissed) {
+ return false;
+ }
// showAmbient == show in shade but not shelf
- if (!showAmbient && notificationData.shouldSuppressStatusBar(entry.key)) {
+ if (!showAmbient && mEntryManager.getNotificationData().shouldSuppressStatusBar(
+ entry.key)) {
return false;
}
@@ -151,28 +160,30 @@ public class NotificationIconAreaController implements DarkReceiver {
/**
* Updates the notifications with the given list of notifications to display.
*/
- public void updateNotificationIcons(NotificationData notificationData) {
+ public void updateNotificationIcons() {
- updateIconsForLayout(notificationData, entry -> entry.icon, mNotificationIcons,
- false /* showAmbient */);
- updateIconsForLayout(notificationData, entry -> entry.expandedIcon, mShelfIcons,
- NotificationShelf.SHOW_AMBIENT_ICONS);
+ updateStatusBarIcons();
+ updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
+ NotificationShelf.SHOW_AMBIENT_ICONS, false /* hideDismissed */);
applyNotificationIconsTint();
}
+ private void updateStatusBarIcons() {
+ updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
+ false /* showAmbient */, true /* hideDismissed */);
+ }
+
/**
* Updates the notification icons for a host layout. This will ensure that the notification
* host layout will have the same icons like the ones in here.
- *
- * @param notificationData the notification data to look up which notifications are relevant
* @param function A function to look up an icon view based on an entry
* @param hostLayout which layout should be updated
* @param showAmbient should ambient notification icons be shown
+ * @param hideDismissed should dismissed icons be hidden
*/
- private void updateIconsForLayout(NotificationData notificationData,
- Function function,
- NotificationIconContainer hostLayout, boolean showAmbient) {
+ private void updateIconsForLayout(Function function,
+ NotificationIconContainer hostLayout, boolean showAmbient, boolean hideDismissed) {
ArrayList toShow = new ArrayList<>(
mNotificationScrollLayout.getChildCount());
@@ -181,7 +192,7 @@ public class NotificationIconAreaController implements DarkReceiver {
View view = mNotificationScrollLayout.getChildAt(i);
if (view instanceof ExpandableNotificationRow) {
NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry();
- if (shouldShowNotificationIcon(ent, notificationData, showAmbient)) {
+ if (shouldShowNotificationIcon(ent, showAmbient, hideDismissed)) {
toShow.add(function.apply(ent));
}
}
@@ -243,10 +254,13 @@ public class NotificationIconAreaController implements DarkReceiver {
final FrameLayout.LayoutParams params = generateIconLayoutParams();
for (int i = 0; i < toShow.size(); i++) {
- View v = toShow.get(i);
+ StatusBarIconView v = toShow.get(i);
// The view might still be transiently added if it was just removed and added again
hostLayout.removeTransientView(v);
if (v.getParent() == null) {
+ if (hideDismissed) {
+ v.setOnDismissListener(mUpdateStatusBarIcons);
+ }
hostLayout.addView(v, i, params);
}
}
@@ -297,7 +311,8 @@ public class NotificationIconAreaController implements DarkReceiver {
mShelfIcons.setDark(dark, false, 0);
}
- public void showIconIsolated(StatusBarIconView icon, Rect absoluteIconPosition) {
- mNotificationIcons.showIconIsolated(icon, absoluteIconPosition);
+ public void showIconIsolated(StatusBarIconView icon, Rect absoluteIconPosition,
+ boolean animated) {
+ mNotificationIcons.showIconIsolated(icon, absoluteIconPosition, animated);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 53ae0f82b0a..46037be3d76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -97,6 +97,34 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
}
}.setDuration(200).setDelay(50);
+ /**
+ * The animation property used for all icons that were not isolated, when the isolation ends.
+ * This just fades the alpha and doesn't affect the movement and has a delay.
+ */
+ private static final AnimationProperties UNISOLATION_PROPERTY_OTHERS
+ = new AnimationProperties() {
+ private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
+
+ @Override
+ public AnimationFilter getAnimationFilter() {
+ return mAnimationFilter;
+ }
+ }.setDuration(HeadsUpAppearanceController.CONTENT_FADE_DURATION).setDelay(
+ HeadsUpAppearanceController.CONTENT_FADE_DURATION);
+
+ /**
+ * The animation property used for the icon when its isolation ends.
+ * This animates the translation back to the right position.
+ */
+ private static final AnimationProperties UNISOLATION_PROPERTY = new AnimationProperties() {
+ private AnimationFilter mAnimationFilter = new AnimationFilter().animateX();
+
+ @Override
+ public AnimationFilter getAnimationFilter() {
+ return mAnimationFilter;
+ }
+ }.setDuration(HeadsUpAppearanceController.CONTENT_FADE_DURATION);
+
public static final int MAX_VISIBLE_ICONS_WHEN_DARK = 5;
public static final int MAX_STATIC_ICONS = 4;
private static final int MAX_DOTS = 3;
@@ -127,6 +155,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
private StatusBarIconView mIsolatedIcon;
private Rect mIsolatedIconLocation;
private int[] mAbsolutePosition = new int[2];
+ private View mIsolatedIconForAnimation;
public NotificationIconContainer(Context context, AttributeSet attrs) {
@@ -219,6 +248,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
mAddAnimationStartIndex = -1;
mCannedAnimationStartIndex = -1;
mDisallowNextAnimation = false;
+ mIsolatedIconForAnimation = null;
}
@Override
@@ -286,8 +316,10 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
mIconStates.remove(child);
if (!isReplacingIcon) {
addTransientView(icon, 0);
+ boolean isIsolatedIcon = child == mIsolatedIcon;
icon.setVisibleState(StatusBarIconView.STATE_HIDDEN, true /* animate */,
- () -> removeTransientView(icon));
+ () -> removeTransientView(icon),
+ isIsolatedIcon ? HeadsUpAppearanceController.CONTENT_FADE_DURATION : 0);
}
}
}
@@ -588,7 +620,11 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
mReplacingIcons = replacingIcons;
}
- public void showIconIsolated(StatusBarIconView icon, Rect absoluteIconPosition) {
+ public void showIconIsolated(StatusBarIconView icon, Rect absoluteIconPosition,
+ boolean animated) {
+ if (animated) {
+ mIsolatedIconForAnimation = mIsolatedIcon;
+ }
mIsolatedIcon = icon;
mIsolatedIconLocation = absoluteIconPosition;
updateState();
@@ -667,6 +703,14 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
animationProperties.setDuration(CANNED_ANIMATION_DURATION);
animate = true;
}
+ if (mIsolatedIconForAnimation != null) {
+ if (view == mIsolatedIconForAnimation) {
+ animationProperties = UNISOLATION_PROPERTY;
+ } else {
+ animationProperties = UNISOLATION_PROPERTY_OTHERS;
+ }
+ animate = true;
+ }
}
icon.setVisibleState(visibleState, animationsAllowed);
icon.setIconColor(iconColor, needsCannedAnimation && animationsAllowed);
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 870dbaf977f..099de1932c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1386,8 +1386,7 @@ public class StatusBar extends SystemUI implements DemoMode,
updateQsExpansionEnabled();
// Let's also update the icons
- mNotificationIconAreaController.updateNotificationIcons(
- mEntryManager.getNotificationData());
+ mNotificationIconAreaController.updateNotificationIcons();
}
@Override
--
GitLab
From 332c23fe4b1c6750e0fc561e74d6bff8219bc761 Mon Sep 17 00:00:00 2001
From: Selim Cinek
Date: Fri, 16 Mar 2018 17:37:50 -0700
Subject: [PATCH 478/488] Added new appear and disappear animations for heads
up
The heads up notifications now appear directly out of the
statusbar icon in a smoother way. This also fixes the
landscape presentation, which was completely wrong
before.
Test: runtest systemui
Change-Id: I84e65d5216f74a9eb1717d3e7c111d66c0b43c65
Fixes: 72748440
---
.../res/layout/heads_up_status_bar_layout.xml | 1 +
.../ActivatableNotificationView.java | 58 +++++++++++---
.../systemui/statusbar/ExpandableView.java | 22 ++++--
.../statusbar/HeadsUpStatusBarView.java | 72 +++++++++++++++--
.../statusbar/StackScrollerDecorView.java | 9 ++-
.../phone/HeadsUpAppearanceController.java | 31 +++++++-
.../phone/NotificationIconAreaController.java | 9 ++-
.../phone/NotificationIconContainer.java | 27 +++++--
.../phone/NotificationPanelView.java | 18 +++++
.../statusbar/stack/AnimationFilter.java | 14 +++-
.../statusbar/stack/ExpandableViewState.java | 3 +-
.../stack/HeadsUpAppearInterpolator.java | 31 ++++----
.../stack/NotificationStackScrollLayout.java | 3 +-
.../statusbar/stack/StackScrollAlgorithm.java | 3 -
.../statusbar/stack/StackStateAnimator.java | 77 ++++++++++++++-----
.../systemui/statusbar/stack/ViewState.java | 16 ++++
16 files changed, 313 insertions(+), 81 deletions(-)
diff --git a/packages/SystemUI/res/layout/heads_up_status_bar_layout.xml b/packages/SystemUI/res/layout/heads_up_status_bar_layout.xml
index 999af23eae0..bacb5c13d40 100644
--- a/packages/SystemUI/res/layout/heads_up_status_bar_layout.xml
+++ b/packages/SystemUI/res/layout/heads_up_status_bar_layout.xml
@@ -20,6 +20,7 @@
android:layout_width="match_parent"
android:visibility="invisible"
android:id="@+id/heads_up_status_bar_view"
+ android:alpha="0"
>