Merge "Enforce policy for camera gesture in keyguard" into oc-dr1-dev
diff --git a/Android.mk b/Android.mk
index 55ea69a..cc34767 100644
--- a/Android.mk
+++ b/Android.mk
@@ -238,6 +238,7 @@
core/java/android/net/INetworkScoreService.aidl \
core/java/android/net/INetworkStatsService.aidl \
core/java/android/net/INetworkStatsSession.aidl \
+ core/java/android/net/ITetheringStatsProvider.aidl \
core/java/android/net/nsd/INsdManager.aidl \
core/java/android/nfc/IAppCallback.aidl \
core/java/android/nfc/INfcAdapter.aidl \
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 204df63..abf48a8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -6480,9 +6480,9 @@
private <T> T instantiate(ClassLoader cl, String className, Context c,
Instantiator<T> instantiator)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
- if (c.getApplicationContext() instanceof Application) {
- T a = instantiator.instantiate((Application) c.getApplicationContext(),
- cl, className);
+ Application app = getApp(c);
+ if (app != null) {
+ T a = instantiator.instantiate(app, cl, className);
if (a != null) return a;
}
return (T) cl.loadClass(className).newInstance();
@@ -6491,14 +6491,25 @@
private <T> T instantiate(ClassLoader cl, String className, Intent intent, Context c,
IntentInstantiator<T> instantiator)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
- if (c.getApplicationContext() instanceof Application) {
- T a = instantiator.instantiate((Application) c.getApplicationContext(),
- cl, className, intent);
+ Application app = getApp(c);
+ if (app != null) {
+ T a = instantiator.instantiate(app, cl, className, intent);
if (a != null) return a;
}
return (T) cl.loadClass(className).newInstance();
}
+ private Application getApp(Context c) {
+ // We need this shortcut to avoid actually calling getApplicationContext() on an Application
+ // because the Application may not return itself for getApplicationContext() because the
+ // API doesn't enforce it.
+ if (c instanceof Application) return (Application) c;
+ if (c.getApplicationContext() instanceof Application) {
+ return (Application) c.getApplicationContext();
+ }
+ return null;
+ }
+
private interface Instantiator<T> {
T instantiate(Application app, ClassLoader cl, String className)
throws ClassNotFoundException, IllegalAccessException, InstantiationException;
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 143d147..d6e3691 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -15,11 +15,6 @@
*/
package android.app;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
-
import android.annotation.SystemApi;
import android.app.NotificationManager.Importance;
import android.content.Intent;
@@ -31,6 +26,11 @@
import android.service.notification.NotificationListenerService;
import android.text.TextUtils;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
import java.io.IOException;
import java.util.Arrays;
@@ -743,7 +743,7 @@
private static String longArrayToString(long[] values) {
StringBuffer sb = new StringBuffer();
- if (values != null) {
+ if (values != null && values.length > 0) {
for (int i = 0; i < values.length - 1; i++) {
sb.append(values[i]).append(DELIMITER);
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 9a01476..f098f2a 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -765,6 +765,16 @@
* constant starts at the high bits.
*/
public static final int CONFIG_FONT_SCALE = 0x40000000;
+ /**
+ * Bit in {@link #configChanges} that indicates that the activity
+ * can itself handle changes to the rotation. Set from the
+ * {@link android.R.attr#configChanges} attribute. This is
+ * not a core resource configuration, but a higher-level value, so its
+ * constant starts at the high bits.
+ * @hide We do not want apps to handle this. It will eventually be moved out of
+ * {@link Configuration}.
+ */
+ public static final int CONFIG_ROTATION = 0x20000000;
/** @hide
* Unfortunately the constants for config changes in native code are
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c67376c..b39f9a5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -200,6 +200,8 @@
// Temporary workaround; allow meta-data to expose components to instant apps
private static final String META_DATA_INSTANT_APPS = "instantapps.clients.allowed";
+ private static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
+
/**
* Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
* @hide
@@ -3639,6 +3641,7 @@
final int innerDepth = parser.getDepth();
int type;
+
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -3815,6 +3818,10 @@
}
}
+ // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after
+ // every activity info has had a chance to set it from its attributes.
+ setMaxAspectRatio(owner);
+
modifySharedLibrariesForBackwardCompatibility(owner);
if (hasDomainURLs(owner)) {
@@ -4258,7 +4265,12 @@
a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
}
- setActivityMaxAspectRatio(a.info, sa, owner);
+ if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
+ && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
+ == TypedValue.TYPE_FLOAT) {
+ a.setMaxAspectRatio(sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio,
+ 0 /*default*/));
+ }
a.info.lockTaskLaunchMode =
sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
@@ -4496,28 +4508,40 @@
}
}
- private void setActivityMaxAspectRatio(ActivityInfo aInfo, TypedArray sa, Package owner) {
- if (aInfo.resizeMode == RESIZE_MODE_RESIZEABLE
- || aInfo.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
- // Resizeable activities can be put in any aspect ratio.
- aInfo.maxAspectRatio = 0;
- return;
- }
-
+ /**
+ * Sets every the max aspect ratio of every child activity that doesn't already have an aspect
+ * ratio set.
+ */
+ private void setMaxAspectRatio(Package owner) {
// Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater.
// NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD.
- float defaultMaxAspectRatio = owner.applicationInfo.targetSdkVersion < O
+ float maxAspectRatio = owner.applicationInfo.targetSdkVersion < O
? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
- if (owner.applicationInfo.maxAspectRatio != 0 ) {
+
+ if (owner.applicationInfo.maxAspectRatio != 0) {
// Use the application max aspect ration as default if set.
- defaultMaxAspectRatio = owner.applicationInfo.maxAspectRatio;
+ maxAspectRatio = owner.applicationInfo.maxAspectRatio;
+ } else if (owner.mAppMetaData != null
+ && owner.mAppMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) {
+ maxAspectRatio = owner.mAppMetaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio);
}
- aInfo.maxAspectRatio = sa.getFloat(
- R.styleable.AndroidManifestActivity_maxAspectRatio, defaultMaxAspectRatio);
- if (aInfo.maxAspectRatio < 1.0f && aInfo.maxAspectRatio != 0) {
- // Ignore any value lesser than 1.0.
- aInfo.maxAspectRatio = 0;
+ for (Activity activity : owner.activities) {
+ // If the max aspect ratio for the activity has already been set, skip.
+ if (activity.hasMaxAspectRatio()) {
+ continue;
+ }
+
+ // By default we prefer to use a values defined on the activity directly than values
+ // defined on the application. We do not check the styled attributes on the activity
+ // as it would have already been set when we processed the activity. We wait to process
+ // the meta data here since this method is called at the end of processing the
+ // application and all meta data is guaranteed.
+ final float activityAspectRatio = activity.metaData != null
+ ? activity.metaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio)
+ : maxAspectRatio;
+
+ activity.setMaxAspectRatio(activityAspectRatio);
}
}
@@ -4658,6 +4682,7 @@
info.windowLayout = target.info.windowLayout;
info.resizeMode = target.info.resizeMode;
info.maxAspectRatio = target.info.maxAspectRatio;
+
info.encryptionAware = info.directBootAware = target.info.directBootAware;
Activity a = new Activity(mParseActivityAliasArgs, info);
@@ -6940,6 +6965,11 @@
public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
public final ActivityInfo info;
+ private boolean mHasMaxAspectRatio;
+
+ private boolean hasMaxAspectRatio() {
+ return mHasMaxAspectRatio;
+ }
public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
super(args, _info);
@@ -6952,6 +6982,23 @@
info.packageName = packageName;
}
+
+ private void setMaxAspectRatio(float maxAspectRatio) {
+ if (info.resizeMode == RESIZE_MODE_RESIZEABLE
+ || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
+ // Resizeable activities can be put in any aspect ratio.
+ return;
+ }
+
+ if (maxAspectRatio < 1.0f && maxAspectRatio != 0) {
+ // Ignore any value lesser than 1.0.
+ return;
+ }
+
+ info.maxAspectRatio = maxAspectRatio;
+ mHasMaxAspectRatio = true;
+ }
+
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("Activity{");
@@ -6971,11 +7018,13 @@
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
+ dest.writeBoolean(mHasMaxAspectRatio);
}
private Activity(Parcel in) {
super(in);
info = in.readParcelable(Object.class.getClassLoader());
+ mHasMaxAspectRatio = in.readBoolean();
for (ActivityIntentInfo aii : intents) {
aii.activity = this;
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index ef279b8..68d4cd8 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1395,7 +1395,7 @@
}
if ((compareUndefined || delta.mRotation != ROTATION_UNDEFINED)
&& mRotation != delta.mRotation) {
- changed |= ActivityInfo.CONFIG_ORIENTATION;
+ changed |= ActivityInfo.CONFIG_ROTATION;
}
if ((compareUndefined || getScreenLayoutNoDirection(delta.screenLayout) !=
(SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED))
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 4bc62b1..e1cd451 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -894,8 +894,9 @@
* to free up resource in sensor system associated with the direct channel.
*
* @param mem A {@link android.os.MemoryFile} shared memory object.
- * @return A {@link android.hardware.SensorDirectChannel} object if successful, null otherwise.
+ * @return A {@link android.hardware.SensorDirectChannel} object.
* @throws NullPointerException when mem is null.
+ * @throws UncheckedIOException if not able to create channel.
* @see SensorDirectChannel#close()
* @see #configureDirectChannel(SensorDirectChannel, Sensor, int)
*/
@@ -916,9 +917,9 @@
* to free up resource in sensor system associated with the direct channel.
*
* @param mem A {@link android.hardware.HardwareBuffer} shared memory object.
- * @return A {@link android.hardware.SensorDirectChannel} object if successful,
- * null otherwise.
+ * @return A {@link android.hardware.SensorDirectChannel} object.
* @throws NullPointerException when mem is null.
+ * @throws UncheckedIOException if not able to create channel.
* @see SensorDirectChannel#close()
* @see #configureDirectChannel(SensorDirectChannel, Sensor, int)
*/
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 1b150bf..90bf896 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -16,28 +16,29 @@
package android.hardware.camera2;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemService;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
import android.content.Context;
-import android.hardware.ICameraService;
-import android.hardware.ICameraServiceListener;
import android.hardware.CameraInfo;
import android.hardware.CameraStatus;
+import android.hardware.ICameraService;
+import android.hardware.ICameraServiceListener;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.legacy.CameraDeviceUserShim;
import android.hardware.camera2.legacy.LegacyMetadataMapper;
-import android.os.IBinder;
import android.os.Binder;
import android.os.DeadObjectException;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
-import android.util.Log;
+import android.os.SystemProperties;
import android.util.ArrayMap;
+import android.util.Log;
import java.util.ArrayList;
@@ -210,7 +211,9 @@
public CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId)
throws CameraAccessException {
CameraCharacteristics characteristics = null;
-
+ if (CameraManagerGlobal.sCameraServiceDisabled) {
+ throw new IllegalArgumentException("No cameras available on device");
+ }
synchronized (mLock) {
/*
* Get the camera characteristics from the camera service directly if it supports it,
@@ -462,6 +465,9 @@
"Handler argument is null, but no looper exists in the calling thread");
}
}
+ if (CameraManagerGlobal.sCameraServiceDisabled) {
+ throw new IllegalArgumentException("No cameras available on device");
+ }
openCameraDeviceUserAsync(cameraId, callback, handler, clientUid);
}
@@ -507,6 +513,9 @@
*/
public void setTorchMode(@NonNull String cameraId, boolean enabled)
throws CameraAccessException {
+ if (CameraManagerGlobal.sCameraServiceDisabled) {
+ throw new IllegalArgumentException("No cameras available on device");
+ }
CameraManagerGlobal.get().setTorchMode(cameraId, enabled);
}
@@ -745,6 +754,9 @@
private CameraManagerGlobal() {
}
+ public static final boolean sCameraServiceDisabled =
+ SystemProperties.getBoolean("config.disable_cameraservice", false);
+
public static CameraManagerGlobal get() {
return gCameraManager;
}
@@ -764,7 +776,7 @@
public ICameraService getCameraService() {
synchronized(mLock) {
connectCameraServiceLocked();
- if (mCameraService == null) {
+ if (mCameraService == null && !sCameraServiceDisabled) {
Log.e(TAG, "Camera service is unavailable");
}
return mCameraService;
@@ -779,7 +791,7 @@
*/
private void connectCameraServiceLocked() {
// Only reconnect if necessary
- if (mCameraService != null) return;
+ if (mCameraService != null || sCameraServiceDisabled) return;
Log.i(TAG, "Connecting to camera service");
diff --git a/core/java/android/net/ITetheringStatsProvider.aidl b/core/java/android/net/ITetheringStatsProvider.aidl
new file mode 100644
index 0000000..769086d
--- /dev/null
+++ b/core/java/android/net/ITetheringStatsProvider.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.NetworkStats;
+
+/**
+ * Interface that allows NetworkManagementService to query for tethering statistics.
+ *
+ * TODO: this does not really need to be an interface since Tethering runs in the same process
+ * as NetworkManagementService. Consider refactoring Tethering to use direct access to
+ * NetworkManagementService instead of using INetworkManagementService, and then deleting this
+ * interface.
+ *
+ * @hide
+ */
+interface ITetheringStatsProvider {
+ NetworkStats getTetherStats();
+}
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 2d9860c..4b79cbb 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -99,7 +99,7 @@
* shut down the tunnel gracefully.</li>
* </ol>
*
- * <p>Services extended this class need to be declared with appropriate
+ * <p>Services extending this class need to be declared with an appropriate
* permission and intent filter. Their access must be secured by
* {@link android.Manifest.permission#BIND_VPN_SERVICE} permission, and
* their intent filter must match {@link #SERVICE_INTERFACE} action. Here
@@ -112,6 +112,13 @@
* </intent-filter>
* </service></pre>
*
+ * <p> The Android system starts a VPN in the background by calling
+ * {@link android.content.Context#startService startService()}. In Android 8.0
+ * (API level 26) and higher, the system places VPN apps on the temporary
+ * whitelist for a short period so the app can start in the background. The VPN
+ * app must promote itself to the foreground after it's launched or the system
+ * will shut down the app.
+ *
* @see Builder
*/
public class VpnService extends Service {
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 92e78bc..3de2174 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -20,6 +20,7 @@
import android.net.InterfaceConfiguration;
import android.net.INetd;
import android.net.INetworkManagementEventObserver;
+import android.net.ITetheringStatsProvider;
import android.net.Network;
import android.net.NetworkStats;
import android.net.RouteInfo;
@@ -207,6 +208,18 @@
void disableNat(String internalInterface, String externalInterface);
/**
+ * Registers a {@code ITetheringStatsProvider} to provide tethering statistics.
+ * All registered providers will be called in order, and their results will be added together.
+ * Netd is always registered as a tethering stats provider.
+ */
+ void registerTetheringStatsProvider(ITetheringStatsProvider provider, String name);
+
+ /**
+ * Unregisters a previously-registered {@code ITetheringStatsProvider}.
+ */
+ void unregisterTetheringStatsProvider(ITetheringStatsProvider provider);
+
+ /**
** PPPD
**/
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 2c6c7f9..7fa1c5a 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -751,7 +751,9 @@
// Block until the ordered broadcast has completed.
condition.block();
- wipeEuiccData(context, wipeEuicc);
+ // TODO(b/63693573): Uncomment this once the pSIM slot is restored as needed
+ // after the ensuing boot. Currently you end up stuck on the eSIM.
+ // wipeEuiccData(context, wipeEuicc);
String shutdownArg = null;
if (shutdown) {
@@ -808,7 +810,8 @@
HandlerThread euiccHandlerThread = new HandlerThread("euiccWipeFinishReceiverThread");
euiccHandlerThread.start();
Handler euiccHandler = new Handler(euiccHandlerThread.getLooper());
- context.registerReceiver(euiccWipeFinishReceiver, filterConsent, null, euiccHandler);
+ context.getApplicationContext()
+ .registerReceiver(euiccWipeFinishReceiver, filterConsent, null, euiccHandler);
if (isWipeEuicc) {
euiccManager.eraseSubscriptions(callbackIntent);
} else {
@@ -831,7 +834,7 @@
Log.e(TAG, "Timeout retaining eUICC data.");
}
}
- context.unregisterReceiver(euiccWipeFinishReceiver);
+ context.getApplicationContext().unregisterReceiver(euiccWipeFinishReceiver);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
if (isWipeEuicc) {
diff --git a/core/java/android/widget/TextInputTimePickerView.java b/core/java/android/widget/TextInputTimePickerView.java
index 11b7514d..0cf8faa 100644
--- a/core/java/android/widget/TextInputTimePickerView.java
+++ b/core/java/android/widget/TextInputTimePickerView.java
@@ -17,6 +17,7 @@
package android.widget;
import android.content.Context;
+import android.os.LocaleList;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextWatcher;
@@ -141,6 +142,9 @@
new InputFilter.LengthFilter(maxCharLength)});
mMinuteEditText.setFilters(new InputFilter[] {
new InputFilter.LengthFilter(maxCharLength)});
+ final LocaleList locales = mContext.getResources().getConfiguration().getLocales();
+ mHourEditText.setImeHintLocales(locales);
+ mMinuteEditText.setImeHintLocales(locales);
}
boolean validateInput() {
diff --git a/core/java/com/android/internal/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java
index 2608698..2648604 100644
--- a/core/java/com/android/internal/colorextraction/ColorExtractor.java
+++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java
@@ -43,10 +43,6 @@
private static final String TAG = "ColorExtractor";
- public static final int FALLBACK_COLOR = 0xff83888d;
-
- private int mMainFallbackColor = FALLBACK_COLOR;
- private int mSecondaryFallbackColor = FALLBACK_COLOR;
private final SparseArray<GradientColors[]> mGradientColors;
private final ArrayList<OnColorsChangedListener> mOnColorsChangedListeners;
private final Context mContext;
@@ -55,7 +51,7 @@
private WallpaperColors mLockColors;
public ColorExtractor(Context context) {
- this(context, new Tonal());
+ this(context, new Tonal(context));
}
@VisibleForTesting
@@ -73,6 +69,9 @@
}
mOnColorsChangedListeners = new ArrayList<>();
+ GradientColors[] systemColors = mGradientColors.get(WallpaperManager.FLAG_SYSTEM);
+ GradientColors[] lockColors = mGradientColors.get(WallpaperManager.FLAG_LOCK);
+
WallpaperManager wallpaperManager = mContext.getSystemService(WallpaperManager.class);
if (wallpaperManager == null) {
Log.w(TAG, "Can't listen to color changes!");
@@ -83,23 +82,18 @@
Trace.beginSection("ColorExtractor#getWallpaperColors");
mSystemColors = wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
mLockColors = wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_LOCK);
-
- GradientColors[] systemColors = mGradientColors.get(
- WallpaperManager.FLAG_SYSTEM);
- extractInto(mSystemColors,
- systemColors[TYPE_NORMAL],
- systemColors[TYPE_DARK],
- systemColors[TYPE_EXTRA_DARK]);
-
- GradientColors[] lockColors = mGradientColors.get(WallpaperManager.FLAG_LOCK);
- extractInto(mLockColors,
- lockColors[TYPE_NORMAL],
- lockColors[TYPE_DARK],
- lockColors[TYPE_EXTRA_DARK]);
- triggerColorsChanged(WallpaperManager.FLAG_SYSTEM
- | WallpaperManager.FLAG_LOCK);
Trace.endSection();
}
+
+ // Initialize all gradients with the current colors
+ extractInto(mSystemColors,
+ systemColors[TYPE_NORMAL],
+ systemColors[TYPE_DARK],
+ systemColors[TYPE_EXTRA_DARK]);
+ extractInto(mLockColors,
+ lockColors[TYPE_NORMAL],
+ lockColors[TYPE_DARK],
+ lockColors[TYPE_EXTRA_DARK]);
}
/**
@@ -181,25 +175,8 @@
private void extractInto(WallpaperColors inWallpaperColors,
GradientColors outGradientColorsNormal, GradientColors outGradientColorsDark,
GradientColors outGradientColorsExtraDark) {
- if (inWallpaperColors == null) {
- applyFallback(outGradientColorsNormal);
- applyFallback(outGradientColorsDark);
- applyFallback(outGradientColorsExtraDark);
- return;
- }
- boolean success = mExtractionType.extractInto(inWallpaperColors, outGradientColorsNormal,
+ mExtractionType.extractInto(inWallpaperColors, outGradientColorsNormal,
outGradientColorsDark, outGradientColorsExtraDark);
- if (!success) {
- applyFallback(outGradientColorsNormal);
- applyFallback(outGradientColorsDark);
- applyFallback(outGradientColorsExtraDark);
- }
- }
-
- private void applyFallback(GradientColors outGradientColors) {
- outGradientColors.setMainColor(mMainFallbackColor);
- outGradientColors.setSecondaryColor(mSecondaryFallbackColor);
- outGradientColors.setSupportsDarkText(false);
}
public void destroy() {
@@ -218,8 +195,8 @@
}
public static class GradientColors {
- private int mMainColor = FALLBACK_COLOR;
- private int mSecondaryColor = FALLBACK_COLOR;
+ private int mMainColor;
+ private int mSecondaryColor;
private boolean mSupportsDarkText;
public void setMainColor(int mainColor) {
diff --git a/core/java/com/android/internal/colorextraction/types/ExtractionType.java b/core/java/com/android/internal/colorextraction/types/ExtractionType.java
index 762b54f..7000e79 100644
--- a/core/java/com/android/internal/colorextraction/types/ExtractionType.java
+++ b/core/java/com/android/internal/colorextraction/types/ExtractionType.java
@@ -38,9 +38,8 @@
* @param outGradientColorsNormal object that should receive normal colors
* @param outGradientColorsDark object that should receive dark colors
* @param outGradientColorsExtraDark object that should receive extra dark colors
- * @return true if successful.
*/
- boolean extractInto(WallpaperColors inWallpaperColors,
+ void extractInto(WallpaperColors inWallpaperColors,
ColorExtractor.GradientColors outGradientColorsNormal,
ColorExtractor.GradientColors outGradientColorsDark,
ColorExtractor.GradientColors outGradientColorsExtraDark);
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index b8ebe30..dbc086c 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -19,15 +19,22 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WallpaperColors;
+import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.util.MathUtils;
import android.util.Range;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.graphics.ColorUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -44,24 +51,68 @@
private static final boolean DEBUG = true;
+ public static final int MAIN_COLOR_LIGHT = 0xffe0e0e0;
+ public static final int SECONDARY_COLOR_LIGHT = 0xff9e9e9e;
+ public static final int MAIN_COLOR_DARK = 0xff212121;
+ public static final int SECONDARY_COLOR_DARK = 0xff000000;
+
+ private final TonalPalette mGreyPalette;
+ private final ArrayList<TonalPalette> mTonalPalettes;
+ private final ArrayList<ColorRange> mBlacklistedColors;
+
// Temporary variable to avoid allocations
private float[] mTmpHSL = new float[3];
+ public Tonal(Context context) {
+
+ ConfigParser parser = new ConfigParser(context);
+ mTonalPalettes = parser.getTonalPalettes();
+ mBlacklistedColors = parser.getBlacklistedColors();
+
+ mGreyPalette = mTonalPalettes.get(0);
+ mTonalPalettes.remove(0);
+ }
+
/**
- * Grab colors from WallpaperColors as set them into GradientColors
+ * Grab colors from WallpaperColors and set them into GradientColors.
+ * Also applies the default gradient in case extraction fails.
*
- * @param inWallpaperColors input
- * @param outColorsNormal colors for normal theme
- * @param outColorsDark colors for dar theme
- * @param outColorsExtraDark colors for extra dark theme
- * @return true if successful
+ * @param inWallpaperColors Input.
+ * @param outColorsNormal Colors for normal theme.
+ * @param outColorsDark Colors for dar theme.
+ * @param outColorsExtraDark Colors for extra dark theme.
*/
- public boolean extractInto(@NonNull WallpaperColors inWallpaperColors,
+ public void extractInto(@Nullable WallpaperColors inWallpaperColors,
+ @NonNull GradientColors outColorsNormal, @NonNull GradientColors outColorsDark,
+ @NonNull GradientColors outColorsExtraDark) {
+ boolean success = runTonalExtraction(inWallpaperColors, outColorsNormal, outColorsDark,
+ outColorsExtraDark);
+ if (!success) {
+ applyFallback(inWallpaperColors, outColorsNormal, outColorsDark, outColorsExtraDark);
+ }
+ }
+
+ /**
+ * Grab colors from WallpaperColors and set them into GradientColors.
+ *
+ * @param inWallpaperColors Input.
+ * @param outColorsNormal Colors for normal theme.
+ * @param outColorsDark Colors for dar theme.
+ * @param outColorsExtraDark Colors for extra dark theme.
+ * @return True if succeeded or false if failed.
+ */
+ private boolean runTonalExtraction(@Nullable WallpaperColors inWallpaperColors,
@NonNull GradientColors outColorsNormal, @NonNull GradientColors outColorsDark,
@NonNull GradientColors outColorsExtraDark) {
+ if (inWallpaperColors == null) {
+ return false;
+ }
+
final List<Color> mainColors = inWallpaperColors.getMainColors();
final int mainColorsSize = mainColors.size();
+ final boolean supportsDarkText = (inWallpaperColors.getColorHints() &
+ WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
if (mainColorsSize == 0) {
return false;
@@ -120,7 +171,6 @@
float[] s = fit(palette.s, hsl[1], fitIndex, 0.0f, 1.0f);
float[] l = fit(palette.l, hsl[2], fitIndex, 0.0f, 1.0f);
- final int textInversionIndex = h.length - 3;
if (DEBUG) {
StringBuilder builder = new StringBuilder("Tonal Palette - index: " + fitIndex +
". Main color: " + Integer.toHexString(getColorInt(fitIndex, h, s, l)) +
@@ -135,21 +185,38 @@
Log.d(TAG, builder.toString());
}
+ int primaryIndex = fitIndex;
+ int mainColor = getColorInt(primaryIndex, h, s, l);
+
+ // We might want use the fallback in case the extracted color is brighter than our
+ // light fallback or darker than our dark fallback.
+ ColorUtils.colorToHSL(mainColor, mTmpHSL);
+ final float mainLuminosity = mTmpHSL[2];
+ ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL);
+ final float lightLuminosity = mTmpHSL[2];
+ if (mainLuminosity > lightLuminosity) {
+ return false;
+ }
+ ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL);
+ final float darkLuminosity = mTmpHSL[2];
+ if (mainLuminosity < darkLuminosity) {
+ return false;
+ }
+
// Normal colors:
// best fit + a 2 colors offset
- int primaryIndex = fitIndex;
+ outColorsNormal.setMainColor(mainColor);
int secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2);
- outColorsNormal.setMainColor(getColorInt(primaryIndex, h, s, l));
outColorsNormal.setSecondaryColor(getColorInt(secondaryIndex, h, s, l));
// Dark colors:
// Stops at 4th color, only lighter if dark text is supported
- if (fitIndex < 2) {
- primaryIndex = 0;
- } else if (fitIndex < textInversionIndex) {
- primaryIndex = Math.min(fitIndex, 3);
- } else {
+ if (supportsDarkText) {
primaryIndex = h.length - 1;
+ } else if (fitIndex < 2) {
+ primaryIndex = 0;
+ } else {
+ primaryIndex = Math.min(fitIndex, 3);
}
secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2);
outColorsDark.setMainColor(getColorInt(primaryIndex, h, s, l));
@@ -157,30 +224,56 @@
// Extra Dark:
// Stay close to dark colors until dark text is supported
- if (fitIndex < 2) {
- primaryIndex = 0;
- } else if (fitIndex < textInversionIndex) {
- primaryIndex = 2;
- } else {
+ if (supportsDarkText) {
primaryIndex = h.length - 1;
+ } else if (fitIndex < 2) {
+ primaryIndex = 0;
+ } else {
+ primaryIndex = 2;
}
secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2);
outColorsExtraDark.setMainColor(getColorInt(primaryIndex, h, s, l));
outColorsExtraDark.setSecondaryColor(getColorInt(secondaryIndex, h, s, l));
- final boolean supportsDarkText = fitIndex >= textInversionIndex;
outColorsNormal.setSupportsDarkText(supportsDarkText);
outColorsDark.setSupportsDarkText(supportsDarkText);
outColorsExtraDark.setSupportsDarkText(supportsDarkText);
if (DEBUG) {
Log.d(TAG, "Gradients: \n\tNormal " + outColorsNormal + "\n\tDark " + outColorsDark
- + "\n\tExtra dark: " + outColorsExtraDark);
+ + "\n\tExtra dark: " + outColorsExtraDark);
}
return true;
}
+ private void applyFallback(@Nullable WallpaperColors inWallpaperColors,
+ GradientColors outColorsNormal, GradientColors outColorsDark,
+ GradientColors outColorsExtraDark) {
+ applyFallback(inWallpaperColors, outColorsNormal);
+ applyFallback(inWallpaperColors, outColorsDark);
+ applyFallback(inWallpaperColors, outColorsExtraDark);
+ }
+
+ /**
+ * Sets the gradient to the light or dark fallbacks based on the current wallpaper colors.
+ *
+ * @param inWallpaperColors Colors to read.
+ * @param outGradientColors Destination.
+ */
+ public static void applyFallback(@Nullable WallpaperColors inWallpaperColors,
+ @NonNull GradientColors outGradientColors) {
+ boolean light = inWallpaperColors != null
+ && (inWallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT)
+ != 0;
+ int innerColor = light ? MAIN_COLOR_LIGHT : MAIN_COLOR_DARK;
+ int outerColor = light ? SECONDARY_COLOR_LIGHT : SECONDARY_COLOR_DARK;
+
+ outGradientColors.setMainColor(innerColor);
+ outGradientColors.setSecondaryColor(outerColor);
+ outGradientColors.setSupportsDarkText(light);
+ }
+
private int getColorInt(int fitIndex, float[] h, float[] s, float[] l) {
mTmpHSL[0] = fract(h[fitIndex]) * 360.0f;
mTmpHSL[1] = s[fitIndex];
@@ -194,7 +287,8 @@
* @return true if color should be avoided
*/
private boolean isBlacklisted(float[] hsl) {
- for (ColorRange badRange: BLACKLISTED_COLORS) {
+ for (int i = mBlacklistedColors.size() - 1; i >= 0; i--) {
+ ColorRange badRange = mBlacklistedColors.get(i);
if (badRange.containsColor(hsl[0], hsl[1], hsl[2])) {
return true;
}
@@ -250,19 +344,25 @@
return minErrorIndex;
}
+ @VisibleForTesting
+ public List<ColorRange> getBlacklistedColors() {
+ return mBlacklistedColors;
+ }
+
@Nullable
- private static TonalPalette findTonalPalette(float h, float s) {
+ private TonalPalette findTonalPalette(float h, float s) {
// Fallback to a grey palette if the color is too desaturated.
// This avoids hue shifts.
if (s < 0.05f) {
- return GREY_PALETTE;
+ return mGreyPalette;
}
TonalPalette best = null;
float error = Float.POSITIVE_INFINITY;
- for (int i = 0; i < TONAL_PALETTES.length; i++) {
- final TonalPalette candidate = TONAL_PALETTES[i];
+ final int tonalPalettesCount = mTonalPalettes.size();
+ for (int i = 0; i < tonalPalettesCount; i++) {
+ final TonalPalette candidate = mTonalPalettes.get(i);
if (h >= candidate.minHue && h <= candidate.maxHue) {
best = candidate;
@@ -316,7 +416,6 @@
+ Arrays.toString(h) + " s: " + Arrays.toString(s) + " l: "
+ Arrays.toString(l));
}
-
this.h = h;
this.s = s;
this.l = l;
@@ -334,430 +433,6 @@
}
}
- // Data definition of Material Design tonal palettes
- // When the sort type is set to TONAL, these palettes are used to find
- // a best fit. Each palette is defined as 22 HSL colors
- private static final TonalPalette[] TONAL_PALETTES = {
- new TonalPalette(
- new float[] {1f, 1f, 0.991f, 0.991f, 0.9833333333333333f, 0f, 0f, 0f,
- 0.01134380453752181f, 0.015625000000000003f, 0.024193548387096798f,
- 0.027397260273972573f, 0.017543859649122865f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.8434782608695652f, 1f, 1f, 1f, 1f,
- 1f},
- new float[] {0.04f, 0.09f, 0.14f, 0.2f, 0.27450980392156865f,
- 0.34901960784313724f, 0.4235294117647059f, 0.5490196078431373f,
- 0.6254901960784314f, 0.6862745098039216f, 0.7568627450980392f,
- 0.8568627450980393f, 0.9254901960784314f}
- ),
- new TonalPalette(
- new float[] {0.638f, 0.638f, 0.6385767790262171f, 0.6301169590643275f,
- 0.6223958333333334f, 0.6151079136690647f, 0.6065400843881856f,
- 0.5986964618249534f, 0.5910746812386157f, 0.5833333333333334f,
- 0.5748031496062993f, 0.5582010582010583f},
- new float[] {1f, 1f, 1f, 1f, 0.9014084507042253f, 0.8128654970760234f,
- 0.7979797979797981f, 0.7816593886462883f, 0.778723404255319f, 1f, 1f,
- 1f},
- new float[] {0.05f, 0.12f, 0.17450980392156862f, 0.2235294117647059f,
- 0.2784313725490196f, 0.3352941176470588f, 0.388235294117647f,
- 0.44901960784313727f, 0.5392156862745098f, 0.6509803921568628f,
- 0.7509803921568627f, 0.8764705882352941f}
- ),
- new TonalPalette(
- new float[] {0.563f, 0.569f, 0.5666f, 0.5669934640522876f, 0.5748031496062993f,
- 0.5595238095238095f, 0.5473118279569893f, 0.5393258426966292f,
- 0.5315955766192734f, 0.524031007751938f, 0.5154711673699016f,
- 0.508080808080808f, 0.5f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.8847736625514403f, 1f, 1f,
- 1f},
- new float[] {0.07f, 0.12f, 0.16f, 0.2f, 0.24901960784313726f,
- 0.27450980392156865f, 0.30392156862745096f, 0.34901960784313724f,
- 0.4137254901960784f, 0.47647058823529415f, 0.5352941176470588f,
- 0.6764705882352942f, 0.8f}
- ),
- new TonalPalette(
- new float[] {0.508f, 0.511f, 0.508f, 0.508f, 0.5082304526748972f,
- 0.5069444444444444f, 0.5f, 0.5f, 0.5f, 0.48724954462659376f,
- 0.4800347222222222f, 0.4755134281200632f, 0.4724409448818897f,
- 0.4671052631578947f},
- new float[] {1f, 1f, 1f, 1f, 1f, 0.8888888888888887f, 0.9242424242424242f, 1f,
- 1f, 0.8133333333333332f, 0.7868852459016393f, 1f, 1f, 1f},
- new float[] {0.04f, 0.06f, 0.08f, 0.12f, 0.1588235294117647f,
- 0.21176470588235297f, 0.25882352941176473f, 0.3f, 0.34901960784313724f,
- 0.44117647058823534f, 0.5215686274509804f, 0.5862745098039216f,
- 0.7509803921568627f, 0.8509803921568627f}
- ),
- new TonalPalette(
- new float[] {0.333f, 0.333f, 0.333f, 0.3333333333333333f, 0.3333333333333333f,
- 0.34006734006734f, 0.34006734006734f, 0.34006734006734f,
- 0.34259259259259256f, 0.3475783475783476f, 0.34767025089605735f,
- 0.3467741935483871f, 0.3703703703703704f},
- new float[] {0.70f, 0.72f, 0.69f, 0.6703296703296703f, 0.728813559322034f,
- 0.5657142857142856f, 0.5076923076923077f, 0.3944223107569721f,
- 0.6206896551724138f, 0.8931297709923666f, 1f, 1f, 1f},
- new float[] {0.05f, 0.08f, 0.14f, 0.1784313725490196f, 0.23137254901960785f,
- 0.3431372549019608f, 0.38235294117647056f, 0.49215686274509807f,
- 0.6588235294117647f, 0.7431372549019608f, 0.8176470588235294f,
- 0.8784313725490196f, 0.9294117647058824f}
- ),
- new TonalPalette(
- new float[] {0.161f, 0.163f, 0.163f, 0.162280701754386f, 0.15032679738562088f,
- 0.15879265091863518f, 0.16236559139784948f, 0.17443868739205526f,
- 0.17824074074074076f, 0.18674698795180725f, 0.18692449355432778f,
- 0.1946778711484594f, 0.18604651162790695f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
- new float[] {0.05f, 0.08f, 0.11f, 0.14901960784313725f, 0.2f,
- 0.24901960784313726f, 0.30392156862745096f, 0.3784313725490196f,
- 0.4235294117647059f, 0.48823529411764705f, 0.6450980392156863f,
- 0.7666666666666666f, 0.8313725490196078f}
- ),
- new TonalPalette(
- new float[] {0.108f, 0.105f, 0.105f, 0.105f, 0.10619469026548674f,
- 0.11924686192468618f, 0.13046448087431692f, 0.14248366013071895f,
- 0.1506024096385542f, 0.16220238095238093f, 0.16666666666666666f,
- 0.16666666666666666f, 0.162280701754386f, 0.15686274509803924f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
- new float[] {0.17f, 0.22f, 0.28f, 0.35f, 0.44313725490196076f,
- 0.46862745098039216f, 0.47843137254901963f, 0.5f, 0.5117647058823529f,
- 0.5607843137254902f, 0.6509803921568628f, 0.7509803921568627f,
- 0.8509803921568627f, 0.9f}
- ),
- new TonalPalette(
- new float[] {0.036f, 0.036f, 0.036f, 0.036f, 0.03561253561253561f,
- 0.05098039215686275f, 0.07516339869281045f, 0.09477124183006536f,
- 0.1150326797385621f, 0.134640522875817f, 0.14640522875816991f,
- 0.1582397003745319f, 0.15773809523809523f, 0.15359477124183002f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
- new float[] {0.19f, 0.26f, 0.34f, 0.39f, 0.4588235294117647f, 0.5f, 0.5f, 0.5f,
- 0.5f, 0.5f, 0.5f, 0.6509803921568628f, 0.7803921568627451f, 0.9f}
- ),
- new TonalPalette(
- new float[] {0.955f, 0.961f, 0.958f, 0.9596491228070175f, 0.9593837535014005f,
- 0.9514767932489452f, 0.943859649122807f, 0.9396825396825397f,
- 0.9395424836601307f, 0.9393939393939394f, 0.9362745098039216f,
- 0.9754098360655739f, 0.9824561403508771f},
- new float[] {0.87f, 0.85f, 0.85f, 0.84070796460177f, 0.8206896551724138f,
- 0.7979797979797981f, 0.7661290322580644f, 0.9051724137931036f,
- 1f, 1f, 1f, 1f, 1f},
- new float[] {0.06f, 0.11f, 0.16f, 0.22156862745098038f, 0.2843137254901961f,
- 0.388235294117647f, 0.48627450980392156f, 0.5450980392156863f,
- 0.6f, 0.6764705882352942f, 0.8f, 0.8803921568627451f,
- 0.9254901960784314f}
- ),
- new TonalPalette(
- new float[] {0.866f, 0.855f, 0.841025641025641f, 0.8333333333333334f,
- 0.8285256410256411f, 0.821522309711286f, 0.8083333333333333f,
- 0.8046594982078853f, 0.8005822416302766f, 0.7842377260981912f,
- 0.7771084337349398f, 0.7747747747747749f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f,
- 0.737142857142857f, 0.6434108527131781f, 0.46835443037974644f},
- new float[] {0.05f, 0.08f, 0.12745098039215685f, 0.15490196078431373f,
- 0.20392156862745098f, 0.24901960784313726f, 0.3137254901960784f,
- 0.36470588235294116f, 0.44901960784313727f, 0.6568627450980392f,
- 0.7470588235294118f, 0.8450980392156863f}
- ),
- new TonalPalette(
- new float[] {0.925f, 0.93f, 0.938f, 0.947f, 0.955952380952381f,
- 0.9681069958847737f, 0.9760479041916167f, 0.9873563218390804f, 0f, 0f,
- 0.009057971014492771f, 0.026748971193415648f,
- 0.041666666666666616f, 0.05303030303030304f},
- new float[] {1f, 1f, 1f, 1f, 1f, 0.8350515463917526f, 0.6929460580912863f,
- 0.6387665198237885f, 0.6914893617021276f, 0.7583892617449666f,
- 0.8070175438596495f, 0.9310344827586209f, 1f, 1f},
- new float[] {0.10f, 0.13f, 0.17f, 0.2f, 0.27450980392156865f,
- 0.3803921568627451f, 0.4725490196078432f, 0.5549019607843138f,
- 0.6313725490196078f, 0.707843137254902f, 0.7764705882352941f,
- 0.8294117647058823f, 0.9058823529411765f, 0.9568627450980391f}
- ),
- new TonalPalette(
- new float[] {0.733f, 0.736f, 0.744f, 0.7514619883040936f, 0.7679738562091503f,
- 0.7802083333333333f, 0.7844311377245509f, 0.796875f,
- 0.8165618448637316f, 0.8487179487179487f, 0.8582375478927203f,
- 0.8562091503267975f, 0.8666666666666667f},
- new float[] {1f, 1f, 1f, 1f, 1f, 0.8163265306122449f, 0.6653386454183268f,
- 0.7547169811320753f, 0.929824561403509f, 0.9558823529411766f,
- 0.9560439560439562f, 1f, 1f},
- new float[] {0.07f, 0.12f, 0.17f, 0.2235294117647059f, 0.3f,
- 0.38431372549019605f, 0.492156862745098f, 0.5843137254901961f,
- 0.6647058823529411f, 0.7333333333333334f, 0.8215686274509804f, 0.9f,
- 0.9411764705882353f}
- ),
- new TonalPalette(
- new float[] {0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
- 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
- 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
- 0.6666666666666666f, 0.6666666666666666f},
- new float[] {0.25f, 0.24590163934426232f, 0.17880794701986752f,
- 0.14606741573033713f, 0.13761467889908252f, 0.14893617021276592f,
- 0.16756756756756758f, 0.20312500000000017f, 0.26086956521739135f,
- 0.29999999999999966f, 0.5000000000000004f},
- new float[] {0.18f, 0.2392156862745098f, 0.296078431372549f,
- 0.34901960784313724f, 0.4274509803921569f, 0.5392156862745098f,
- 0.6372549019607843f, 0.7490196078431373f, 0.8196078431372549f,
- 0.8823529411764706f, 0.9372549019607843f}
- ),
- new TonalPalette(
- new float[] {0.938f, 0.944f, 0.952f, 0.961f, 0.9678571428571429f,
- 0.9944812362030905f, 0f, 0f,
- 0.0047348484848484815f, 0.00316455696202532f, 0f,
- 0.9980392156862745f, 0.9814814814814816f, 0.9722222222222221f},
- new float[] {1f, 1f, 1f, 1f, 1f, 0.7023255813953488f, 0.6638655462184874f,
- 0.6521739130434782f, 0.7719298245614035f, 0.8315789473684211f,
- 0.6867469879518071f, 0.7264957264957265f, 0.8181818181818182f,
- 0.8181818181818189f},
- new float[] {0.08f, 0.13f, 0.18f, 0.23f, 0.27450980392156865f,
- 0.4215686274509804f,
- 0.4666666666666667f, 0.503921568627451f, 0.5529411764705883f,
- 0.6274509803921569f, 0.6745098039215687f, 0.7705882352941176f,
- 0.892156862745098f, 0.9568627450980391f}
- ),
- new TonalPalette(
- new float[] {0.88f, 0.888f, 0.897f, 0.9052287581699346f, 0.9112021857923498f,
- 0.9270152505446624f, 0.9343137254901961f, 0.9391534391534391f,
- 0.9437984496124031f, 0.943661971830986f, 0.9438943894389439f,
- 0.9426229508196722f, 0.9444444444444444f},
- new float[] {1f, 1f, 1f, 1f, 0.8133333333333332f, 0.7927461139896375f,
- 0.7798165137614679f, 0.7777777777777779f, 0.8190476190476191f,
- 0.8255813953488372f, 0.8211382113821142f, 0.8133333333333336f,
- 0.8000000000000006f},
- new float[] {0.08f, 0.12f, 0.16f, 0.2f, 0.29411764705882354f,
- 0.3784313725490196f, 0.42745098039215684f, 0.4764705882352941f,
- 0.5882352941176471f, 0.6627450980392157f, 0.7588235294117647f,
- 0.8529411764705882f, 0.9411764705882353f}
- ),
- new TonalPalette(
- new float[] {0.669f, 0.680f, 0.6884057971014492f, 0.6974789915966387f,
- 0.7079889807162534f, 0.7154471544715447f, 0.7217741935483872f,
- 0.7274143302180687f, 0.7272727272727273f, 0.7258064516129031f,
- 0.7252252252252251f, 0.7333333333333333f},
- new float[] {0.81f, 0.81f, 0.8214285714285715f, 0.6878612716763006f,
- 0.6080402010050251f, 0.5774647887323943f, 0.5391304347826086f,
- 0.46724890829694316f, 0.4680851063829788f, 0.462686567164179f,
- 0.45679012345678977f, 0.4545454545454551f},
- new float[] {0.12f, 0.16f, 0.2196078431372549f, 0.33921568627450976f,
- 0.39019607843137255f, 0.4176470588235294f, 0.45098039215686275f,
- 0.5509803921568628f, 0.6313725490196078f, 0.7372549019607844f,
- 0.8411764705882353f, 0.9352941176470588f}
- ),
- new TonalPalette(
- new float[] {0.6470588235294118f, 0.6516666666666667f, 0.6464174454828661f,
- 0.6441441441441442f, 0.6432748538011696f, 0.6416666666666667f,
- 0.6402439024390243f, 0.6412429378531074f, 0.6435185185185186f,
- 0.6428571428571429f},
- new float[] {0.8095238095238095f, 0.6578947368421053f, 0.5721925133689839f,
- 0.5362318840579711f, 0.5f, 0.4424778761061947f, 0.44086021505376327f,
- 0.44360902255639095f, 0.4499999999999997f, 0.4375000000000006f},
- new float[] {0.16470588235294117f, 0.2980392156862745f, 0.36666666666666664f,
- 0.40588235294117647f, 0.44705882352941173f,
- 0.5568627450980392f, 0.6352941176470588f, 0.7392156862745098f,
- 0.8431372549019608f, 0.9372549019607843f}
- ),
- new TonalPalette(
- new float[] {0.469f, 0.46732026143790845f, 0.4718614718614719f,
- 0.4793650793650794f, 0.48071625344352614f, 0.4829683698296837f,
- 0.484375f, 0.4841269841269842f, 0.48444444444444457f,
- 0.48518518518518516f, 0.4907407407407408f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 0.6274509803921569f, 0.41832669322709176f,
- 0.41899441340782106f, 0.4128440366972478f, 0.4090909090909088f},
- new float[] {0.07f, 0.1f, 0.15098039215686274f, 0.20588235294117646f,
- 0.2372549019607843f, 0.26862745098039215f, 0.4f, 0.5078431372549019f,
- 0.6490196078431372f, 0.7862745098039216f, 0.9137254901960784f}
- ),
- new TonalPalette(
- new float[] {0.542f, 0.5444444444444444f, 0.5555555555555556f,
- 0.5555555555555556f, 0.553763440860215f, 0.5526315789473684f,
- 0.5555555555555556f, 0.5555555555555555f, 0.5555555555555556f,
- 0.5512820512820514f, 0.5666666666666667f},
- new float[] {0.25f, 0.24590163934426232f, 0.19148936170212766f,
- 0.1791044776119403f, 0.18343195266272191f, 0.18446601941747576f,
- 0.1538461538461539f, 0.15625000000000003f, 0.15328467153284678f,
- 0.15662650602409653f, 0.151515151515151f},
- new float[] {0.05f, 0.1196078431372549f, 0.1843137254901961f,
- 0.2627450980392157f,
- 0.33137254901960783f, 0.403921568627451f, 0.5411764705882354f,
- 0.6235294117647059f, 0.7313725490196079f, 0.8372549019607843f,
- 0.9352941176470588f}
- ),
- new TonalPalette(
- new float[] {0.022222222222222223f, 0.02469135802469136f, 0.031249999999999997f,
- 0.03947368421052631f, 0.04166666666666668f,
- 0.043650793650793655f, 0.04411764705882352f, 0.04166666666666652f,
- 0.04444444444444459f, 0.05555555555555529f},
- new float[] {0.33333333333333337f, 0.2783505154639175f, 0.2580645161290323f,
- 0.25675675675675674f, 0.2528735632183908f, 0.17500000000000002f,
- 0.15315315315315312f, 0.15189873417721522f,
- 0.15789473684210534f, 0.15789473684210542f},
- new float[] {0.08823529411764705f, 0.19019607843137254f, 0.2431372549019608f,
- 0.2901960784313725f, 0.3411764705882353f, 0.47058823529411764f,
- 0.5647058823529412f, 0.6901960784313725f, 0.8137254901960784f,
- 0.9254901960784314f}
- ),
- new TonalPalette(
- new float[] {0.027f, 0.03f, 0.038f, 0.044f, 0.050884955752212385f,
- 0.07254901960784313f, 0.0934640522875817f,
- 0.10457516339869281f, 0.11699346405228758f,
- 0.1255813953488372f, 0.1268939393939394f, 0.12533333333333332f,
- 0.12500000000000003f, 0.12777777777777777f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
- new float[] {0.25f, 0.3f, 0.35f, 0.4f, 0.44313725490196076f, 0.5f, 0.5f, 0.5f,
- 0.5f, 0.5784313725490196f,
- 0.6549019607843137f, 0.7549019607843137f, 0.8509803921568627f,
- 0.9411764705882353f}
- )
- };
-
- private static final TonalPalette GREY_PALETTE = new TonalPalette(
- new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f},
- new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f},
- new float[]{0.08f, 0.11f, 0.14901960784313725f, 0.2f, 0.2980392156862745f, 0.4f,
- 0.4980392156862745f, 0.6196078431372549f, 0.7176470588235294f,
- 0.8196078431372549f, 0.9176470588235294f, 0.9490196078431372f}
- );
-
- @SuppressWarnings("WeakerAccess")
- @VisibleForTesting
- public static final ColorRange[] BLACKLISTED_COLORS = new ColorRange[] {
-
- // Red
- new ColorRange(
- new Range<>(0f, 20f) /* H */,
- new Range<>(0.7f, 1f) /* S */,
- new Range<>(0.21f, 0.79f)) /* L */,
- new ColorRange(
- new Range<>(0f, 20f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.355f, 0.653f)),
-
- // Red Orange
- new ColorRange(
- new Range<>(20f, 40f),
- new Range<>(0.7f, 1f),
- new Range<>(0.28f, 0.643f)),
- new ColorRange(
- new Range<>(20f, 40f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.414f, 0.561f)),
- new ColorRange(
- new Range<>(20f, 40f),
- new Range<>(0f, 3f),
- new Range<>(0.343f, 0.584f)),
-
- // Orange
- new ColorRange(
- new Range<>(40f, 60f),
- new Range<>(0.7f, 1f),
- new Range<>(0.173f, 0.349f)),
- new ColorRange(
- new Range<>(40f, 60f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.233f, 0.427f)),
- new ColorRange(
- new Range<>(40f, 60f),
- new Range<>(0f, 0.3f),
- new Range<>(0.231f, 0.484f)),
-
- // Yellow 60
- new ColorRange(
- new Range<>(60f, 80f),
- new Range<>(0.7f, 1f),
- new Range<>(0.488f, 0.737f)),
- new ColorRange(
- new Range<>(60f, 80f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.673f, 0.837f)),
-
- // Yellow Green 80
- new ColorRange(
- new Range<>(80f, 100f),
- new Range<>(0.7f, 1f),
- new Range<>(0.469f, 0.61f)),
-
- // Yellow green 100
- new ColorRange(
- new Range<>(100f, 120f),
- new Range<>(0.7f, 1f),
- new Range<>(0.388f, 0.612f)),
- new ColorRange(
- new Range<>(100f, 120f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.424f, 0.541f)),
-
- // Green
- new ColorRange(
- new Range<>(120f, 140f),
- new Range<>(0.7f, 1f),
- new Range<>(0.375f, 0.52f)),
- new ColorRange(
- new Range<>(120f, 140f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.435f, 0.524f)),
-
- // Green Blue 140
- new ColorRange(
- new Range<>(140f, 160f),
- new Range<>(0.7f, 1f),
- new Range<>(0.496f, 0.641f)),
-
- // Seafoam
- new ColorRange(
- new Range<>(160f, 180f),
- new Range<>(0.7f, 1f),
- new Range<>(0.496f, 0.567f)),
-
- // Cyan
- new ColorRange(
- new Range<>(180f, 200f),
- new Range<>(0.7f, 1f),
- new Range<>(0.52f, 0.729f)),
-
- // Blue
- new ColorRange(
- new Range<>(220f, 240f),
- new Range<>(0.7f, 1f),
- new Range<>(0.396f, 0.571f)),
- new ColorRange(
- new Range<>(220f, 240f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.425f, 0.551f)),
-
- // Blue Purple 240
- new ColorRange(
- new Range<>(240f, 260f),
- new Range<>(0.7f, 1f),
- new Range<>(0.418f, 0.639f)),
- new ColorRange(
- new Range<>(220f, 240f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.441f, 0.576f)),
-
- // Blue Purple 260
- new ColorRange(
- new Range<>(260f, 280f),
- new Range<>(0.3f, 1f), // Bigger range
- new Range<>(0.461f, 0.553f)),
-
- // Fuchsia
- new ColorRange(
- new Range<>(300f, 320f),
- new Range<>(0.7f, 1f),
- new Range<>(0.484f, 0.588f)),
- new ColorRange(
- new Range<>(300f, 320f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.48f, 0.592f)),
-
- // Pink
- new ColorRange(
- new Range<>(320f, 340f),
- new Range<>(0.7f, 1f),
- new Range<>(0.466f, 0.629f)),
-
- // Soft red
- new ColorRange(
- new Range<>(340f, 360f),
- new Range<>(0.7f, 1f),
- new Range<>(0.437f, 0.596f))
- };
-
/**
* Representation of an HSL color range.
* <ul>
@@ -802,4 +477,124 @@
return String.format("H: %s, S: %s, L %s", mHue, mSaturation, mLightness);
}
}
-}
+
+ @VisibleForTesting
+ public static class ConfigParser {
+ private final ArrayList<TonalPalette> mTonalPalettes;
+ private final ArrayList<ColorRange> mBlacklistedColors;
+
+ public ConfigParser(Context context) {
+ mTonalPalettes = new ArrayList<>();
+ mBlacklistedColors = new ArrayList<>();
+
+ // Load all palettes and the blacklist from an XML.
+ try {
+ XmlPullParser parser = context.getResources().getXml(R.xml.color_extraction);
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_DOCUMENT ||
+ eventType == XmlPullParser.END_TAG) {
+ // just skip
+ } else if (eventType == XmlPullParser.START_TAG) {
+ String tagName = parser.getName();
+ if (tagName.equals("palettes")) {
+ parsePalettes(parser);
+ } else if (tagName.equals("blacklist")) {
+ parseBlacklist(parser);
+ }
+ } else {
+ throw new XmlPullParserException("Invalid XML event " + eventType + " - "
+ + parser.getName(), parser, null);
+ }
+ eventType = parser.next();
+ }
+ } catch (XmlPullParserException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public ArrayList<TonalPalette> getTonalPalettes() {
+ return mTonalPalettes;
+ }
+
+ public ArrayList<ColorRange> getBlacklistedColors() {
+ return mBlacklistedColors;
+ }
+
+ private void parseBlacklist(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ parser.require(XmlPullParser.START_TAG, null, "blacklist");
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ // Starts by looking for the entry tag
+ if (name.equals("range")) {
+ mBlacklistedColors.add(readRange(parser));
+ parser.next();
+ } else {
+ throw new XmlPullParserException("Invalid tag: " + name, parser, null);
+ }
+ }
+ }
+
+ private ColorRange readRange(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ parser.require(XmlPullParser.START_TAG, null, "range");
+ float[] h = readFloatArray(parser.getAttributeValue(null, "h"));
+ float[] s = readFloatArray(parser.getAttributeValue(null, "s"));
+ float[] l = readFloatArray(parser.getAttributeValue(null, "l"));
+
+ if (h == null || s == null || l == null) {
+ throw new XmlPullParserException("Incomplete range tag.", parser, null);
+ }
+
+ return new ColorRange(new Range<>(h[0], h[1]), new Range<>(s[0], s[1]),
+ new Range<>(l[0], l[1]));
+ }
+
+ private void parsePalettes(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ parser.require(XmlPullParser.START_TAG, null, "palettes");
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ // Starts by looking for the entry tag
+ if (name.equals("palette")) {
+ mTonalPalettes.add(readPalette(parser));
+ parser.next();
+ } else {
+ throw new XmlPullParserException("Invalid tag: " + name);
+ }
+ }
+ }
+
+ private TonalPalette readPalette(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ parser.require(XmlPullParser.START_TAG, null, "palette");
+
+ float[] h = readFloatArray(parser.getAttributeValue(null, "h"));
+ float[] s = readFloatArray(parser.getAttributeValue(null, "s"));
+ float[] l = readFloatArray(parser.getAttributeValue(null, "l"));
+
+ if (h == null || s == null || l == null) {
+ throw new XmlPullParserException("Incomplete range tag.", parser, null);
+ }
+
+ return new TonalPalette(h, s, l);
+ }
+
+ private float[] readFloatArray(String attributeValue)
+ throws IOException, XmlPullParserException {
+ String[] tokens = attributeValue.replaceAll(" ", "").replaceAll("\n", "").split(",");
+ float[] numbers = new float[tokens.length];
+ for (int i = 0; i < tokens.length; i++) {
+ numbers[i] = Float.parseFloat(tokens[i]);
+ }
+ return numbers;
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9e61a99..21cf95f 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -132,6 +132,9 @@
bootTimingsTraceLog.traceBegin("PreloadResources");
preloadResources();
bootTimingsTraceLog.traceEnd(); // PreloadResources
+ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
+ nativePreloadAppProcessHALs();
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
preloadOpenGL();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
@@ -184,6 +187,8 @@
System.loadLibrary("jnigraphics");
}
+ native private static void nativePreloadAppProcessHALs();
+
private static void preloadOpenGL() {
String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false) &&
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index 2cf58d7..4f9e8a5 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -143,7 +143,6 @@
try {
return FileUtils.readTextFile(lastHeaderFile, 0, null);
} catch (IOException e) {
- Slog.e(TAG, "Error reading " + lastHeaderFile, e);
return null;
}
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 7e71ce9..a228d34 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -188,6 +188,7 @@
"com_android_internal_os_FuseAppLoop.cpp",
"com_android_internal_os_PathClassLoaderFactory.cpp",
"com_android_internal_os_Zygote.cpp",
+ "com_android_internal_os_ZygoteInit.cpp",
"com_android_internal_util_VirtualRefBasePtr.cpp",
"com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp",
"hwbinder/EphemeralStorage.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 1adc6dd..daf815a 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -206,6 +206,7 @@
extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
extern int register_com_android_internal_os_PathClassLoaderFactory(JNIEnv* env);
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
+extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
static AndroidRuntime* gCurRuntime = NULL;
@@ -245,7 +246,7 @@
methods, NELEM(methods));
}
-int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
+int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env)
{
const JNINativeMethod methods[] = {
{ "nativeZygoteInit", "()V",
@@ -1286,7 +1287,7 @@
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
- REG_JNI(register_com_android_internal_os_ZygoteInit),
+ REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
@@ -1388,6 +1389,7 @@
REG_JNI(register_android_os_MemoryFile),
REG_JNI(register_com_android_internal_os_PathClassLoaderFactory),
REG_JNI(register_com_android_internal_os_Zygote),
+ REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_camera2_CameraMetadata),
diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp
new file mode 100644
index 0000000..258a55c
--- /dev/null
+++ b/core/jni/com_android_internal_os_ZygoteInit.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Zygote"
+
+#include <ui/GraphicBufferMapper.h>
+
+#include "core_jni_helpers.h"
+
+namespace {
+
+void android_internal_os_ZygoteInit_nativePreloadAppProcessHALs(JNIEnv* env, jclass) {
+ android::GraphicBufferMapper::preloadHal();
+ // Add preloading here for other HALs that are (a) always passthrough, and
+ // (b) loaded by most app processes.
+}
+
+const JNINativeMethod gMethods[] = {
+ { "nativePreloadAppProcessHALs", "()V",
+ (void*)android_internal_os_ZygoteInit_nativePreloadAppProcessHALs },
+};
+
+} // anonymous namespace
+
+namespace android {
+
+int register_com_android_internal_os_ZygoteInit(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "com/android/internal/os/ZygoteInit",
+ gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4059c30..ae115d3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3817,6 +3817,11 @@
<service android:name="com.android.server.PreloadsFileCacheExpirationJobService"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
+
+ <service android:name="com.android.server.camera.CameraStatsJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
</application>
</manifest>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2d7a5d3..2f81f43 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1485,6 +1485,7 @@
<java-symbol type="xml" name="global_keys" />
<java-symbol type="xml" name="default_zen_mode_config" />
<java-symbol type="xml" name="sms_7bit_translation_table" />
+ <java-symbol type="xml" name="color_extraction" />
<java-symbol type="raw" name="color_fade_vert" />
<java-symbol type="raw" name="color_fade_frag" />
diff --git a/core/res/res/xml/color_extraction.xml b/core/res/res/xml/color_extraction.xml
new file mode 100644
index 0000000..7d52b20
--- /dev/null
+++ b/core/res/res/xml/color_extraction.xml
@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<colorextraction>
+ <!-- List of material color palettes in HSL -->
+ <palettes>
+ <!-- Grey scale -->
+ <palette h="0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f"
+ s="0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f"
+ l="0.08f, 0.11f, 0.14901960784313725f, 0.2f, 0.2980392156862745f, 0.4f,
+ 0.4980392156862745f, 0.6196078431372549f, 0.7176470588235294f,
+ 0.8196078431372549f, 0.9176470588235294f, 0.9490196078431372f"/>
+ <!-- All colors -->
+ <palette h="1,1,0.991,0.991,0.9833333333333333,0,0,0,
+ 0.01134380453752181,0.015625000000000003,0.024193548387096798,
+ 0.027397260273972573,0.017543859649122865"
+ s="1,1,1,1,1,1,1,0.8434782608695652,1,1,1,1,1"
+ l="0.04,0.09,0.14,0.2,0.27450980392156865,
+ 0.34901960784313724,0.4235294117647059,0.5490196078431373,
+ 0.6254901960784314,0.6862745098039216,0.7568627450980392,
+ 0.8568627450980393,0.9254901960784314"/>
+ <palette h="0.638,0.638,0.6385767790262171,0.6301169590643275,
+ 0.6223958333333334,0.6151079136690647,0.6065400843881856,
+ 0.5986964618249534,0.5910746812386157,0.5833333333333334,
+ 0.5748031496062993,0.5582010582010583"
+ s="1,1,1,1,0.9014084507042253,0.8128654970760234,
+ 0.7979797979797981,0.7816593886462883,0.778723404255319,1,1,1"
+ l="0.05,0.12,0.17450980392156862,0.2235294117647059,
+ 0.2784313725490196,0.3352941176470588,0.388235294117647,
+ 0.44901960784313727,0.5392156862745098,0.6509803921568628,
+ 0.7509803921568627,0.8764705882352941"/>
+ <palette h="0.563,0.569,0.5666,0.5669934640522876,0.5748031496062993,
+ 0.5595238095238095,0.5473118279569893,0.5393258426966292,
+ 0.5315955766192734,0.524031007751938,0.5154711673699016,
+ 0.508080808080808,0.5"
+ s="1,1,1,1,1,1,1,1,1,0.8847736625514403,1,1,1"
+ l="0.07,0.12,0.16,0.2,0.24901960784313726,
+ 0.27450980392156865,0.30392156862745096,0.34901960784313724,
+ 0.4137254901960784,0.47647058823529415,0.5352941176470588,
+ 0.6764705882352942,0.8"/>
+ <palette h="0.508,0.511,0.508,0.508,0.5082304526748972,
+ 0.5069444444444444,0.5,0.5,0.5,0.48724954462659376,
+ 0.4800347222222222,0.4755134281200632,0.4724409448818897,
+ 0.4671052631578947"
+ s="1,1,1,1,1,0.8888888888888887,0.9242424242424242,1,
+ 1,0.8133333333333332,0.7868852459016393,1,1,1"
+ l="0.04,0.06,0.08,0.12,0.1588235294117647,
+ 0.21176470588235297,0.25882352941176473,0.3,0.34901960784313724,
+ 0.44117647058823534,0.5215686274509804,0.5862745098039216,
+ 0.7509803921568627,0.8509803921568627"/>
+ <palette h="0.333,0.333,0.333,0.3333333333333333,0.3333333333333333,
+ 0.34006734006734,0.34006734006734,0.34006734006734,
+ 0.34259259259259256,0.3475783475783476,0.34767025089605735,
+ 0.3467741935483871,0.3703703703703704"
+ s="0.70,0.72,0.69,0.6703296703296703,0.728813559322034,
+ 0.5657142857142856,0.5076923076923077,0.3944223107569721,
+ 0.6206896551724138,0.8931297709923666,1,1,1"
+ l="0.05,0.08,0.14,0.1784313725490196,0.23137254901960785,
+ 0.3431372549019608,0.38235294117647056,0.49215686274509807,
+ 0.6588235294117647,0.7431372549019608,0.8176470588235294,
+ 0.8784313725490196,0.9294117647058824"/>
+ <palette h="0.161,0.163,0.163,0.162280701754386,0.15032679738562088,
+ 0.15879265091863518,0.16236559139784948,0.17443868739205526,
+ 0.17824074074074076,0.18674698795180725,0.18692449355432778,
+ 0.1946778711484594,0.18604651162790695"
+ s="1,1,1,1,1,1,1,1,1,1,1,1,1"
+ l="0.05,0.08,0.11,0.14901960784313725,0.2,
+ 0.24901960784313726,0.30392156862745096,0.3784313725490196,
+ 0.4235294117647059,0.48823529411764705,0.6450980392156863,
+ 0.7666666666666666,0.8313725490196078"/>
+ <palette h="0.108,0.105,0.105,0.105,0.10619469026548674,
+ 0.11924686192468618,0.13046448087431692,0.14248366013071895,
+ 0.1506024096385542,0.16220238095238093,0.16666666666666666,
+ 0.16666666666666666,0.162280701754386,0.15686274509803924"
+ s="1,1,1,1,1,1,1,1,1,1,1,1,1,1"
+ l="0.17,0.22,0.28,0.35,0.44313725490196076,
+ 0.46862745098039216,0.47843137254901963,0.5,0.5117647058823529,
+ 0.5607843137254902,0.6509803921568628,0.7509803921568627,
+ 0.8509803921568627,0.9"/>
+ <palette h="0.036,0.036,0.036,0.036,0.03561253561253561,
+ 0.05098039215686275,0.07516339869281045,0.09477124183006536,
+ 0.1150326797385621,0.134640522875817,0.14640522875816991,
+ 0.1582397003745319,0.15773809523809523,0.15359477124183002"
+ s="1,1,1,1,1,1,1,1,1,1,1,1,1,1"
+ l="0.19,0.26,0.34,0.39,0.4588235294117647,0.5,0.5,0.5,
+ 0.5,0.5,0.5,0.6509803921568628,0.7803921568627451,0.9"/>
+ <palette h="0.955,0.961,0.958,0.9596491228070175,0.9593837535014005,
+ 0.9514767932489452,0.943859649122807,0.9396825396825397,
+ 0.9395424836601307,0.9393939393939394,0.9362745098039216,
+ 0.9754098360655739,0.9824561403508771"
+ s="0.87,0.85,0.85,0.84070796460177,0.8206896551724138,
+ 0.7979797979797981,0.7661290322580644,0.9051724137931036,
+ 1,1,1,1,1"
+ l="0.06,0.11,0.16,0.22156862745098038,0.2843137254901961,
+ 0.388235294117647,0.48627450980392156,0.5450980392156863,
+ 0.6,0.6764705882352942,0.8,0.8803921568627451,
+ 0.9254901960784314"/>
+ <palette h="0.866,0.855,0.841025641025641,0.8333333333333334,
+ 0.8285256410256411,0.821522309711286,0.8083333333333333,
+ 0.8046594982078853,0.8005822416302766,0.7842377260981912,
+ 0.7771084337349398,0.7747747747747749"
+ s="1,1,1,1,1,1,1,1,1,
+ 0.737142857142857,0.6434108527131781,0.46835443037974644"
+ l="0.05,0.08,0.12745098039215685,0.15490196078431373,
+ 0.20392156862745098,0.24901960784313726,0.3137254901960784,
+ 0.36470588235294116,0.44901960784313727,0.6568627450980392,
+ 0.7470588235294118,0.8450980392156863"/>
+ <palette h="0.925,0.93,0.938,0.947,0.955952380952381,
+ 0.9681069958847737,0.9760479041916167,0.9873563218390804,0,0,
+ 0.009057971014492771,0.026748971193415648,
+ 0.041666666666666616,0.05303030303030304"
+ s="1,1,1,1,1,0.8350515463917526,0.6929460580912863,
+ 0.6387665198237885,0.6914893617021276,0.7583892617449666,
+ 0.8070175438596495,0.9310344827586209,1,1"
+ l="0.10,0.13,0.17,0.2,0.27450980392156865,
+ 0.3803921568627451,0.4725490196078432,0.5549019607843138,
+ 0.6313725490196078,0.707843137254902,0.7764705882352941,
+ 0.8294117647058823,0.9058823529411765,0.9568627450980391"/>
+ <palette h="0.733,0.736,0.744,0.7514619883040936,0.7679738562091503,
+ 0.7802083333333333,0.7844311377245509,0.796875,
+ 0.8165618448637316,0.8487179487179487,0.8582375478927203,
+ 0.8562091503267975,0.8666666666666667"
+ s="1,1,1,1,1,0.8163265306122449,0.6653386454183268,
+ 0.7547169811320753,0.929824561403509,0.9558823529411766,
+ 0.9560439560439562,1,1"
+ l="0.07,0.12,0.17,0.2235294117647059,0.3,
+ 0.38431372549019605,0.492156862745098,0.5843137254901961,
+ 0.6647058823529411,0.7333333333333334,0.8215686274509804,0.9,
+ 0.9411764705882353"/>
+ <palette h="0.6666666666666666,0.6666666666666666,0.6666666666666666,
+ 0.6666666666666666,0.6666666666666666,0.6666666666666666,
+ 0.6666666666666666,0.6666666666666666,0.6666666666666666,
+ 0.6666666666666666,0.6666666666666666"
+ s="0.25,0.24590163934426232,0.17880794701986752,
+ 0.14606741573033713,0.13761467889908252,0.14893617021276592,
+ 0.16756756756756758,0.20312500000000017,0.26086956521739135,
+ 0.29999999999999966,0.5000000000000004"
+ l="0.18,0.2392156862745098,0.296078431372549,
+ 0.34901960784313724,0.4274509803921569,0.5392156862745098,
+ 0.6372549019607843,0.7490196078431373,0.8196078431372549,
+ 0.8823529411764706,0.9372549019607843"/>
+ <palette h="0.938,0.944,0.952,0.961,0.9678571428571429,
+ 0.9944812362030905,0,0,
+ 0.0047348484848484815,0.00316455696202532,0,
+ 0.9980392156862745,0.9814814814814816,0.9722222222222221"
+ s="1,1,1,1,1,0.7023255813953488,0.6638655462184874,
+ 0.6521739130434782,0.7719298245614035,0.8315789473684211,
+ 0.6867469879518071,0.7264957264957265,0.8181818181818182,
+ 0.8181818181818189"
+ l="0.08,0.13,0.18,0.23,0.27450980392156865,
+ 0.4215686274509804,
+ 0.4666666666666667,0.503921568627451,0.5529411764705883,
+ 0.6274509803921569,0.6745098039215687,0.7705882352941176,
+ 0.892156862745098,0.9568627450980391"/>
+ <palette h="0.88,0.888,0.897,0.9052287581699346,0.9112021857923498,
+ 0.9270152505446624,0.9343137254901961,0.9391534391534391,
+ 0.9437984496124031,0.943661971830986,0.9438943894389439,
+ 0.9426229508196722,0.9444444444444444"
+ s="1,1,1,1,0.8133333333333332,0.7927461139896375,
+ 0.7798165137614679,0.7777777777777779,0.8190476190476191,
+ 0.8255813953488372,0.8211382113821142,0.8133333333333336,
+ 0.8000000000000006"
+ l="0.08,0.12,0.16,0.2,0.29411764705882354,
+ 0.3784313725490196,0.42745098039215684,0.4764705882352941,
+ 0.5882352941176471,0.6627450980392157,0.7588235294117647,
+ 0.8529411764705882,0.9411764705882353"/>
+ <palette h="0.669,0.680,0.6884057971014492,0.6974789915966387,
+ 0.7079889807162534,0.7154471544715447,0.7217741935483872,
+ 0.7274143302180687,0.7272727272727273,0.7258064516129031,
+ 0.7252252252252251,0.7333333333333333"
+ s="0.81,0.81,0.8214285714285715,0.6878612716763006,
+ 0.6080402010050251,0.5774647887323943,0.5391304347826086,
+ 0.46724890829694316,0.4680851063829788,0.462686567164179,
+ 0.45679012345678977,0.4545454545454551"
+ l="0.12,0.16,0.2196078431372549,0.33921568627450976,
+ 0.39019607843137255,0.4176470588235294,0.45098039215686275,
+ 0.5509803921568628,0.6313725490196078,0.7372549019607844,
+ 0.8411764705882353,0.9352941176470588"/>
+ <palette h="0.6470588235294118,0.6516666666666667,0.6464174454828661,
+ 0.6441441441441442,0.6432748538011696,0.6416666666666667,
+ 0.6402439024390243,0.6412429378531074,0.6435185185185186,
+ 0.6428571428571429"
+ s="0.8095238095238095,0.6578947368421053,0.5721925133689839,
+ 0.5362318840579711,0.5,0.4424778761061947,0.44086021505376327,
+ 0.44360902255639095,0.4499999999999997,0.4375000000000006"
+ l="0.16470588235294117,0.2980392156862745,0.36666666666666664,
+ 0.40588235294117647,0.44705882352941173,
+ 0.5568627450980392,0.6352941176470588,0.7392156862745098,
+ 0.8431372549019608,0.9372549019607843"/>
+ <palette h="0.469,0.46732026143790845,0.4718614718614719,
+ 0.4793650793650794,0.48071625344352614,0.4829683698296837,
+ 0.484375,0.4841269841269842,0.48444444444444457,
+ 0.48518518518518516,0.4907407407407408"
+ s="1,1,1,1,1,1,0.6274509803921569,0.41832669322709176,
+ 0.41899441340782106,0.4128440366972478,0.4090909090909088"
+ l="0.07,0.1,0.15098039215686274,0.20588235294117646,
+ 0.2372549019607843,0.26862745098039215,0.4,0.5078431372549019,
+ 0.6490196078431372,0.7862745098039216,0.9137254901960784"/>
+ <palette h="0.542,0.5444444444444444,0.5555555555555556,
+ 0.5555555555555556,0.553763440860215,0.5526315789473684,
+ 0.5555555555555556,0.5555555555555555,0.5555555555555556,
+ 0.5512820512820514,0.5666666666666667"
+ s="0.25,0.24590163934426232,0.19148936170212766,
+ 0.1791044776119403,0.18343195266272191,0.18446601941747576,
+ 0.1538461538461539,0.15625000000000003,0.15328467153284678,
+ 0.15662650602409653,0.151515151515151"
+ l="0.05,0.1196078431372549,0.1843137254901961,
+ 0.2627450980392157,
+ 0.33137254901960783,0.403921568627451,0.5411764705882354,
+ 0.6235294117647059,0.7313725490196079,0.8372549019607843,
+ 0.9352941176470588"/>
+ <palette h="0.022222222222222223,0.02469135802469136,0.031249999999999997,
+ 0.03947368421052631,0.04166666666666668,
+ 0.043650793650793655,0.04411764705882352,0.04166666666666652,
+ 0.04444444444444459,0.05555555555555529"
+ s="0.33333333333333337,0.2783505154639175,0.2580645161290323,
+ 0.25675675675675674,0.2528735632183908,0.17500000000000002,
+ 0.15315315315315312,0.15189873417721522,
+ 0.15789473684210534,0.15789473684210542"
+ l="0.08823529411764705,0.19019607843137254,0.2431372549019608,
+ 0.2901960784313725,0.3411764705882353,0.47058823529411764,
+ 0.5647058823529412,0.6901960784313725,0.8137254901960784,
+ 0.9254901960784314"/>
+ <palette h="0.027,0.03,0.038,0.044,0.050884955752212385,
+ 0.07254901960784313,0.0934640522875817,
+ 0.10457516339869281,0.11699346405228758,
+ 0.1255813953488372,0.1268939393939394,0.12533333333333332,
+ 0.12500000000000003,0.12777777777777777"
+ s="1,1,1,1,1,1,1,1,1,1,1,1,1,1"
+ l="0.25,0.3,0.35,0.4,0.44313725490196076,0.5,0.5,0.5,
+ 0.5,0.5784313725490196,
+ 0.6549019607843137,0.7549019607843137,0.8509803921568627,
+ 0.9411764705882353"/>
+ </palettes>
+ <blacklist>
+ <!-- Red -->
+ <range h="0, 20"
+ s="0.7, 1"
+ l="0.21, 0.79"/>
+ <range h="0, 20"
+ s="0.3, 0.7"
+ l="0.355, 0.653"/>
+ <!-- Red Orange -->
+ <range h="20, 40"
+ s="0.7, 1"
+ l="0.28, 0.643"/>
+ <range h="20, 40"
+ s="0.3, 0.7"
+ l="0.414, 0.561"/>
+ <range h="20, 40"
+ s="0, 3"
+ l="0.343, 0.584"/>
+ <!-- Orange -->
+ <range h="40, 60"
+ s="0.7, 1"
+ l="0.173, 0.349"/>
+ <range h="40, 60"
+ s="0.3, 0.7"
+ l="0.233, 0.427"/>
+ <range h="40, 60"
+ s="0, 0.3"
+ l="0.231, 0.484"/>
+ <!-- Yellow 60 -->
+ <range h="60, 80"
+ s="0.7, 1"
+ l="0.488, 0.737"/>
+ <range h="60, 80"
+ s="0.3, 0.7"
+ l="0.673, 0.837"/>
+ <!-- Yellow Green 80 -->
+ <range h="80, 100"
+ s="0.7, 1"
+ l="0.469, 0.61"/>
+ <!-- Yellow green 100 -->
+ <range h="100, 120"
+ s="0.7, 1"
+ l="0.388, 0.612"/>
+ <range h="100, 120"
+ s="0.3, 0.7"
+ l="0.424, 0.541"/>
+ <!-- Green -->
+ <range h="120, 140"
+ s="0.7, 1"
+ l="0.375, 0.52"/>
+ <range h="120, 140"
+ s="0.3, 0.7"
+ l="0.435, 0.524"/>
+ <!-- Green Blue 140 -->
+ <range h="140, 160"
+ s="0.7, 1"
+ l="0.496, 0.641"/>
+ <!-- Seaoam -->
+ <range h="160, 180"
+ s="0.7, 1"
+ l="0.496, 0.567"/>
+ <!-- Cyan -->
+ <range h="180, 200"
+ s="0.7, 1"
+ l="0.52, 0.729"/>
+ <!-- Blue -->
+ <range h="220, 240"
+ s="0.7, 1"
+ l="0.396, 0.571"/>
+ <range h="220, 240"
+ s="0.3, 0.7"
+ l="0.425, 0.551"/>
+ <!-- Blue Purple 240 -->
+ <range h="240, 260"
+ s="0.7, 1"
+ l="0.418, 0.639"/>
+ <range h="220, 240"
+ s="0.3, 0.7"
+ l="0.441, 0.576"/>
+ <!-- Blue Purple 260 -->
+ <range h="260, 280"
+ s="0.3, 1"
+ l="0.461, 0.553"/>
+ <!-- Fuchsia -->
+ <range h="300, 320"
+ s="0.7, 1"
+ l="0.484, 0.588"/>
+ <range h="300, 320"
+ s="0.3, 0.7"
+ l="0.48, 0.592"/>
+ <!-- Pink -->
+ <range h="320, 340"
+ s="0.7, 1"
+ l="0.466, 0.629"/>
+ <!-- Soft red -->
+ <range h="340, 360"
+ s="0.7, 1"
+ l="0.437, 0.596"/>
+ </blacklist>
+</colorextraction>
\ No newline at end of file
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index a487632..7e4f1d0 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -30,6 +30,7 @@
import android.net.Proxy;
import android.net.Uri;
import android.net.http.SslError;
+import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.ArrayMap;
@@ -56,6 +57,7 @@
import java.lang.InterruptedException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.util.Objects;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -285,6 +287,18 @@
return null;
}
+ private static String host(URL url) {
+ if (url == null) {
+ return null;
+ }
+ return url.getHost();
+ }
+
+ private static String sanitizeURL(URL url) {
+ // In non-Debug build, only show host to avoid leaking private info.
+ return Build.IS_DEBUGGABLE ? Objects.toString(url) : host(url);
+ }
+
private void testForCaptivePortal() {
// TODO: reuse NetworkMonitor facilities for consistent captive portal detection.
new Thread(new Runnable() {
@@ -338,6 +352,8 @@
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
getResources().getDisplayMetrics());
private int mPagesLoaded;
+ // the host of the page that this webview is currently loading. Can be null when undefined.
+ private String mHostname;
// If we haven't finished cleaning up the history, don't allow going back.
public boolean allowBack() {
@@ -345,8 +361,8 @@
}
@Override
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
- if (url.contains(mBrowserBailOutToken)) {
+ public void onPageStarted(WebView view, String urlString, Bitmap favicon) {
+ if (urlString.contains(mBrowserBailOutToken)) {
mLaunchBrowser = true;
done(Result.WANTED_AS_IS);
return;
@@ -354,11 +370,17 @@
// The first page load is used only to cause the WebView to
// fetch the proxy settings. Don't update the URL bar, and
// don't check if the captive portal is still there.
- if (mPagesLoaded == 0) return;
+ if (mPagesLoaded == 0) {
+ return;
+ }
+ final URL url = makeURL(urlString);
+ Log.d(TAG, "onPageSarted: " + sanitizeURL(url));
+ mHostname = host(url);
// For internally generated pages, leave URL bar listing prior URL as this is the URL
// the page refers to.
- if (!url.startsWith(INTERNAL_ASSETS)) {
- getActionBar().setSubtitle(getHeaderSubtitle(url));
+ if (!urlString.startsWith(INTERNAL_ASSETS)) {
+ String subtitle = (url != null) ? getHeaderSubtitle(url) : urlString;
+ getActionBar().setSubtitle(subtitle);
}
getProgressBar().setVisibility(View.VISIBLE);
testForCaptivePortal();
@@ -400,15 +422,18 @@
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
- logMetricsEvent(MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR);
- Log.w(TAG, "SSL error (error: " + error.getPrimaryError() + " host: " +
- // Only show host to avoid leaking private info.
- Uri.parse(error.getUrl()).getHost() + " certificate: " +
- error.getCertificate() + "); displaying SSL warning.");
- final String sslErrorPage = makeSslErrorPage();
- if (VDBG) {
- Log.d(TAG, sslErrorPage);
+ final URL url = makeURL(error.getUrl());
+ final String host = host(url);
+ Log.d(TAG, String.format("SSL error: %s, url: %s, certificate: %s",
+ error.getPrimaryError(), sanitizeURL(url), error.getCertificate()));
+ if (url == null || !Objects.equals(host, mHostname)) {
+ // Ignore ssl errors for resources coming from a different hostname than the page
+ // that we are currently loading, and only cancel the request.
+ handler.cancel();
+ return;
}
+ logMetricsEvent(MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR);
+ final String sslErrorPage = makeSslErrorPage();
view.loadDataWithBaseURL(INTERNAL_ASSETS, sslErrorPage, "text/HTML", "UTF-8", null);
}
@@ -493,16 +518,13 @@
return getString(R.string.action_bar_label);
}
- private String getHeaderSubtitle(String urlString) {
- URL url = makeURL(urlString);
- if (url == null) {
- return urlString;
- }
+ private String getHeaderSubtitle(URL url) {
+ String host = host(url);
final String https = "https";
if (https.equals(url.getProtocol())) {
- return https + "://" + url.getHost();
+ return https + "://" + host;
}
- return url.getHost();
+ return host;
}
private void logMetricsEvent(int event) {
diff --git a/packages/SettingsLib/res/layout/preference_two_target.xml b/packages/SettingsLib/res/layout/preference_two_target.xml
index 7000940d..2309ec6 100644
--- a/packages/SettingsLib/res/layout/preference_two_target.xml
+++ b/packages/SettingsLib/res/layout/preference_two_target.xml
@@ -18,6 +18,7 @@
<!-- Based off preference_material_settings.xml except that ripple on only on the left side. -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
@@ -50,8 +51,8 @@
android:id="@android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:maxWidth="48dp"
- android:maxHeight="48dp" />
+ settings:maxWidth="48dp"
+ settings:maxHeight="48dp" />
</LinearLayout>
<RelativeLayout
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 5662703..00bb4a9 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -36,7 +36,7 @@
<string name="wifi_no_internet" msgid="3880396223819116454">"No hi ha accés a Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Desat per <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Connectada automàticament a través de: %1$s"</string>
- <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connectada automàticament a través d\'un proveïdor de valoració de la xarxa"</string>
+ <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connectada automàticament a través d\'un proveïdor de valoració de xarxes"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Connectada mitjançant %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Disponible mitjançant %1$s"</string>
<string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connectada, sense Internet"</string>
@@ -186,7 +186,7 @@
<string name="wifi_aggressive_handover" msgid="5309131983693661320">"Transferència agressiva de Wi-Fi a mòbil"</string>
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permet sempre cerca de Wi-Fi en ininerància"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Dades mòbils sempre actives"</string>
- <string name="tethering_hardware_offload" msgid="7470077827090325814">"Acceleració per maquinari per a la compartició de xarxa"</string>
+ <string name="tethering_hardware_offload" msgid="7470077827090325814">"Acceleració per maquinari per compartir la xarxa"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desactiva el volum absolut"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Activa el so al mateix canal"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versió AVRCP de Bluetooth"</string>
@@ -218,7 +218,7 @@
<string name="allow_mock_location_summary" msgid="317615105156345626">"Permet les ubicacions simulades"</string>
<string name="debug_view_attributes" msgid="6485448367803310384">"Inspecció d\'atributs de visualització"</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Mantén les dades mòbils sempre actives, fins i tot quan la Wi‑Fi està activada (per canviar de xarxa ràpidament)."</string>
- <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Fes servir l\'acceleració per maquinari per a la compartició de xarxa, si està disponible"</string>
+ <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Fes servir l\'acceleració per maquinari per compartir la xarxa, si està disponible"</string>
<string name="adb_warning_title" msgid="6234463310896563253">"Voleu permetre la depuració USB?"</string>
<string name="adb_warning_message" msgid="7316799925425402244">"La depuració USB només està indicada per a activitats de desenvolupament. Fes-la servir intercanviar dades entre l\'ordinador i el dispositiu, per instal·lar aplicacions al dispositiu sense rebre notificacions i per llegir dades de registre."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"Vols revocar l\'accés a la depuració d\'USB dels ordinadors que has autoritzat anteriorment?"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index e2e0e62..4a6f12d 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -104,11 +104,11 @@
<string name="process_kernel_label" msgid="3916858646836739323">"SO Android"</string>
<string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicaciones eliminadas"</string>
<string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Usuarios y aplicaciones eliminados"</string>
- <string name="tether_settings_title_usb" msgid="6688416425801386511">"Compartir por USB"</string>
+ <string name="tether_settings_title_usb" msgid="6688416425801386511">"Compartir conexión por USB"</string>
<string name="tether_settings_title_wifi" msgid="3277144155960302049">"Zona Wi-Fi portátil"</string>
- <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Compartir por Bluetooth"</string>
- <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Compartir Internet"</string>
- <string name="tether_settings_title_all" msgid="8356136101061143841">"Compartir Internet y zona Wi-Fi"</string>
+ <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Compartir conexión por Bluetooth"</string>
+ <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Compartir conexión"</string>
+ <string name="tether_settings_title_all" msgid="8356136101061143841">"Compartir conexión y zona Wi-Fi"</string>
<string name="managed_user_title" msgid="8109605045406748842">"Todas las aplicaciones de trabajo"</string>
<string name="user_guest" msgid="8475274842845401871">"Invitado"</string>
<string name="unknown" msgid="1592123443519355854">"Desconocido"</string>
@@ -162,7 +162,7 @@
<string name="development_settings_summary" msgid="1815795401632854041">"Establecer opciones de desarrollo de aplicaciones"</string>
<string name="development_settings_not_available" msgid="4308569041701535607">"Las opciones de desarrollador no están disponibles para este usuario"</string>
<string name="vpn_settings_not_available" msgid="956841430176985598">"Los ajustes de VPN no están disponibles para este usuario"</string>
- <string name="tethering_settings_not_available" msgid="6765770438438291012">"Los ajustes para compartir Internet no están disponibles para este usuario"</string>
+ <string name="tethering_settings_not_available" msgid="6765770438438291012">"Los ajustes para compartir conexión no están disponibles para este usuario"</string>
<string name="apn_settings_not_available" msgid="7873729032165324000">"Los ajustes del nombre de punto de acceso no están disponibles para este usuario"</string>
<string name="enable_adb" msgid="7982306934419797485">"Depuración por USB"</string>
<string name="enable_adb_summary" msgid="4881186971746056635">"Activar el modo de depuración cuando el dispositivo esté conectado por USB"</string>
@@ -186,7 +186,7 @@
<string name="wifi_aggressive_handover" msgid="5309131983693661320">"Transferencia agresiva de Wi-Fi a móvil"</string>
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir siempre búsquedas de Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Datos móviles siempre activos"</string>
- <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración por hardware para conexión mediante dispositivo portátil"</string>
+ <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración por hardware para conexión compartida"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inhabilitar volumen absoluto"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Habilitar tono de llamada por Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versión AVRCP del Bluetooth"</string>
@@ -218,7 +218,7 @@
<string name="allow_mock_location_summary" msgid="317615105156345626">"Permitir ubicaciones simuladas"</string>
<string name="debug_view_attributes" msgid="6485448367803310384">"Inspección de atributos de vista"</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Mantén los datos móviles siempre activos, aunque la conexión Wi‑Fi esté activada (para cambiar de red rápidamente)."</string>
- <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Usar la aceleración por hardware para conexión mediante dispositivo portátil si está disponible"</string>
+ <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Usar la conexión compartida con aceleración por hardware si está disponible"</string>
<string name="adb_warning_title" msgid="6234463310896563253">"¿Permitir depuración por USB?"</string>
<string name="adb_warning_message" msgid="7316799925425402244">"La depuración por USB solo está indicada para actividades de desarrollo. Puedes utilizarla para intercambiar datos entre el ordenador y el dispositivo, para instalar aplicaciones en el dispositivo sin recibir notificaciones y para leer datos de registro."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"¿Quieres revocar el acceso a la depuración por USB de todos los ordenadores que has autorizado?"</string>
diff --git a/packages/SettingsLib/res/values/attrs.xml b/packages/SettingsLib/res/values/attrs.xml
index a8a1793..6d852df 100644
--- a/packages/SettingsLib/res/values/attrs.xml
+++ b/packages/SettingsLib/res/values/attrs.xml
@@ -48,4 +48,9 @@
<attr name="footerPreferenceStyle" format="reference" />
+ <declare-styleable name="PreferenceImageView">
+ <attr name="maxWidth" format="dimension" />
+ <attr name="maxHeight" format="dimension" />
+ </declare-styleable>
+
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java b/packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java
index 512049f..c79b1466d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java
@@ -68,10 +68,8 @@
public void onClick(DialogInterface dialog, int which) {
UserHandle user = mSelectedTile.userHandle.get(which);
// Show menu on top level items.
- mSelectedTile.intent.putExtra(SettingsDrawerActivity.EXTRA_SHOW_MENU, true);
mSelectedTile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
getActivity().startActivityAsUser(mSelectedTile.intent, user);
- ((SettingsDrawerActivity) getActivity()).onProfileTileOpen();
}
public static void updateUserHandlesIfNeeded(Context context, Tile tile) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index ec41415..ec3b520 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1170,8 +1170,9 @@
if (nc != null) {
if (nc.hasCapability(nc.NET_CAPABILITY_CAPTIVE_PORTAL)) {
- return context.getString(
- com.android.internal.R.string.network_available_sign_in);
+ int id = context.getResources()
+ .getIdentifier("network_available_sign_in", "string", "android");
+ return context.getString(id);
} else if (!nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
return context.getString(R.string.wifi_connected_no_internet);
}
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_access_alarms_big.xml b/packages/SystemUI/res-keyguard/drawable/ic_access_alarms_big.xml
index fd385fc..fffa0bd 100644
--- a/packages/SystemUI/res-keyguard/drawable/ic_access_alarms_big.xml
+++ b/packages/SystemUI/res-keyguard/drawable/ic_access_alarms_big.xml
@@ -19,6 +19,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="?attr/bgProtectSecondaryTextColor"
+ android:fillColor="@android:color/white"
android:pathData="M21.35,6.49c-0.35,0.42 -0.98,0.47 -1.4,0.12l-3.07,-2.57a1,1 0,1 1,1.29 -1.53l3.07,2.57c0.42,0.35 0.47,0.98 0.11,1.41zM7.24,2.63a1,1 0,0 0,-1.41 -0.13L2.77,5.07A0.996,0.996 0,1 0,4.05 6.6l3.06,-2.57c0.43,-0.35 0.48,-0.98 0.13,-1.4zM11.75,8c-0.41,0 -0.75,0.34 -0.75,0.75v4.68c0,0.35 0.18,0.68 0.49,0.86l3.65,2.19c0.34,0.2 0.78,0.1 0.98,-0.24a0.71,0.71 0,0 0,-0.25 -0.99l-3.37,-2v-4.5c0,-0.41 -0.34,-0.75 -0.75,-0.75zM12,5.9c-3.91,0 -7.1,3.18 -7.1,7.1s3.19,7.1 7.1,7.1 7.1,-3.18 7.1,-7.1 -3.19,-7.1 -7.1,-7.1M12,4a9,9 0,1 1,-0.001 18.001A9,9 0,0 1,12 4z" />
</vector>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index a0850f4..7d125046 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -39,6 +39,8 @@
android:layout_height="wrap_content"
android:drawablePadding="6dp"
android:drawableStart="@drawable/ic_access_alarms_big"
+ android:drawableTint="?attr/bgProtectSecondaryTextColor"
+ android:drawableTintMode="src_in"
android:textColor="?attr/bgProtectSecondaryTextColor"
android:letterSpacing="0.15"
style="@style/widget_label"
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 795f20e..9eceeb4 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -38,7 +38,7 @@
<item name="android:paddingBottom">-16dp</item>
</style>
<style name="Keyguard.ImageButton.NumPadEnter" parent="@android:style/Widget.ImageButton">
- <item name="android:tint">?attr/bgProtectTextColor</item>
+ <item name="android:tint">@color/background_protected</item>
</style>
<style name="Widget.TextView.NumPadKey.Klondike" parent="Widget.TextView.NumPadKey">
<item name="android:textSize">12sp</item>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 91d6b24..1705f79 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -267,6 +267,12 @@
<!-- Doze: alpha to apply to small icons when dozing -->
<integer name="doze_small_icon_alpha">222</integer><!-- 87% of 0xff -->
+ <!-- Doze: the brightness value to use for the lower brightness AOD mode -->
+ <integer name="config_doze_aod_brightness_low">6</integer>
+
+ <!-- Doze: the brightness value to use for the higher brightness AOD mode -->
+ <integer name="config_doze_aod_brightness_high">27</integer>
+
<!-- Doze: whether the double tap sensor reports 2D touch coordinates -->
<bool name="doze_double_tap_reports_touch_coordinates">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8807393..1ff7ae4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -814,6 +814,9 @@
burn-in on AOD -->
<dimen name="burn_in_prevention_offset_y">50dp</dimen>
+ <!-- padding between the notification stack and the keyguard status view when dozing -->
+ <dimen name="dozing_stack_padding">10dp</dimen>
+
<dimen name="corner_size">16dp</dimen>
<dimen name="top_padding">0dp</dimen>
<dimen name="bottom_padding">48dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index e375a21..b61c5b5 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -308,6 +308,7 @@
<item name="darkIconTheme">@style/DualToneDarkTheme</item>
<item name="bgProtectTextColor">?android:attr/textColorPrimaryInverse</item>
<item name="bgProtectSecondaryTextColor">?android:attr/textColorSecondaryInverse</item>
+ <item name="android:colorControlHighlight">?android:attr/textColorSecondaryInverse</item>
<item name="*android:lockPatternStyle">@style/LockPatternStyle</item>
</style>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 2262869..5005f9d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -19,9 +19,11 @@
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.PorterDuff;
import android.os.UserHandle;
import android.support.v4.graphics.ColorUtils;
import android.text.TextUtils;
@@ -56,11 +58,14 @@
private TextView mOwnerInfo;
private ViewGroup mClockContainer;
private ChargingView mBatteryDoze;
+ private View mKeyguardStatusArea;
private View[] mVisibleInDoze;
private boolean mPulsing;
- private float mDarkAmount;
+ private float mDarkAmount = 0;
private int mTextColor;
+ private int mDateTextColor;
+ private int mAlarmTextColor;
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@@ -126,8 +131,11 @@
mClockView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
mOwnerInfo = findViewById(R.id.owner_info);
mBatteryDoze = findViewById(R.id.battery_doze);
- mVisibleInDoze = new View[]{mBatteryDoze, mClockView};
+ mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
+ mVisibleInDoze = new View[]{mBatteryDoze, mClockView, mKeyguardStatusArea};
mTextColor = mClockView.getCurrentTextColor();
+ mDateTextColor = mDateView.getCurrentTextColor();
+ mAlarmTextColor = mAlarmStatusView.getCurrentTextColor();
boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
setEnableMarquee(shouldMarquee);
@@ -186,8 +194,7 @@
}
public int getClockBottom() {
- return mClockView.getBottom() +
- ((MarginLayoutParams) mClockView.getLayoutParams()).bottomMargin;
+ return mKeyguardStatusArea.getBottom();
}
public float getClockTextSize() {
@@ -304,6 +311,10 @@
updateDozeVisibleViews();
mBatteryDoze.setDark(dark);
mClockView.setTextColor(ColorUtils.blendARGB(mTextColor, Color.WHITE, darkAmount));
+ mDateView.setTextColor(ColorUtils.blendARGB(mDateTextColor, Color.WHITE, darkAmount));
+ int blendedAlarmColor = ColorUtils.blendARGB(mAlarmTextColor, Color.WHITE, darkAmount);
+ mAlarmStatusView.setTextColor(blendedAlarmColor);
+ mAlarmStatusView.setCompoundDrawableTintList(ColorStateList.valueOf(blendedAlarmColor));
}
public void setPulsing(boolean pulsing) {
diff --git a/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java b/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
index c382882..6296297 100644
--- a/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
+++ b/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
@@ -14,56 +14,74 @@
package com.android.systemui;
+import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.IDockedStackListener;
import android.view.WindowManagerGlobal;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
import java.util.function.Consumer;
/**
* Utility wrapper to listen for whether or not a docked stack exists, to be
* used for things like the different overview icon in that mode.
*/
-public class DockedStackExistsListener extends IDockedStackListener.Stub {
+public class DockedStackExistsListener {
private static final String TAG = "DockedStackExistsListener";
- private final Consumer<Boolean> mCallback;
+ private static ArrayList<WeakReference<Consumer<Boolean>>> sCallbacks = new ArrayList<>();
- private DockedStackExistsListener(Consumer<Boolean> callback) {
- mCallback = callback;
+ static {
+ try {
+ WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(
+ new IDockedStackListener.Stub() {
+ @Override
+ public void onDividerVisibilityChanged(boolean b) throws RemoteException {
+
+ }
+
+ @Override
+ public void onDockedStackExistsChanged(boolean exists)
+ throws RemoteException {
+ DockedStackExistsListener.onDockedStackExistsChanged(exists);
+ }
+
+ @Override
+ public void onDockedStackMinimizedChanged(boolean b, long l, boolean b1)
+ throws RemoteException {
+
+ }
+
+ @Override
+ public void onAdjustedForImeChanged(boolean b, long l)
+ throws RemoteException {
+
+ }
+
+ @Override
+ public void onDockSideChanged(int i) throws RemoteException {
+
+ }
+ });
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed registering docked stack exists listener", e);
+ }
}
- @Override
- public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
- }
- @Override
- public void onDockedStackExistsChanged(final boolean exists) throws RemoteException {
- mCallback.accept(exists);
- }
-
- @Override
- public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
- boolean isHomeStackResizable) throws RemoteException {
- }
-
- @Override
- public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
- throws RemoteException {
- }
-
- @Override
- public void onDockSideChanged(int newDockSide) throws RemoteException {
+ private static void onDockedStackExistsChanged(boolean exists) {
+ synchronized (sCallbacks) {
+ sCallbacks.removeIf(wf -> wf.get() == null);
+ sCallbacks.forEach(wf -> wf.get().accept(exists));
+ }
}
public static void register(Consumer<Boolean> callback) {
- try {
- WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(
- new DockedStackExistsListener(callback));
- } catch (RemoteException e) {
- Log.e(TAG, "Failed registering docked stack exists listener", e);
+ synchronized (sCallbacks) {
+ sCallbacks.add(new WeakReference<>(callback));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 6571294..907a79e 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -199,7 +199,7 @@
// Load background image dimensions, if we haven't saved them yet
if (mBackgroundWidth <= 0 || mBackgroundHeight <= 0) {
// Need to load the image to get dimensions
- loadWallpaper(forDraw, true /* needsReset */);
+ loadWallpaper(forDraw, false /* needsReset */);
if (DEBUG) {
Log.d(TAG, "Reloading, redoing updateSurfaceSize later.");
}
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index ccb8117..44cf003 100644
--- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -16,6 +16,7 @@
package com.android.systemui.colorextraction;
+import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.Context;
import android.os.Handler;
@@ -41,16 +42,16 @@
private final GradientColors mWpHiddenColors;
public SysuiColorExtractor(Context context) {
- this(context, new Tonal(), true);
+ this(context, new Tonal(context), true);
}
@VisibleForTesting
public SysuiColorExtractor(Context context, ExtractionType type, boolean registerVisibility) {
super(context, type);
-
mWpHiddenColors = new GradientColors();
- mWpHiddenColors.setMainColor(FALLBACK_COLOR);
- mWpHiddenColors.setSecondaryColor(FALLBACK_COLOR);
+
+ WallpaperColors systemColors = getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
+ updateDefaultGradients(systemColors);
if (registerVisibility) {
try {
@@ -71,6 +72,24 @@
}
}
+ private void updateDefaultGradients(WallpaperColors colors) {
+ Tonal.applyFallback(colors, mWpHiddenColors);
+ }
+
+ @Override
+ public void onColorsChanged(WallpaperColors colors, int which) {
+ super.onColorsChanged(colors, which);
+
+ if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
+ updateDefaultGradients(colors);
+ }
+ }
+
+ @VisibleForTesting
+ GradientColors getFallbackColors() {
+ return mWpHiddenColors;
+ }
+
/**
* Get TYPE_NORMAL colors when wallpaper is visible, or fallback otherwise.
*
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index e461986..28a45aa 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -23,6 +23,9 @@
import android.hardware.SensorManager;
import android.os.Handler;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+
/**
* Controls the screen brightness when dozing.
*/
@@ -34,6 +37,9 @@
private final Sensor mLightSensor;
private boolean mRegistered;
+ private final int mHighBrightness;
+ private final int mLowBrightness;
+
public DozeScreenBrightness(Context context, DozeMachine.Service service,
SensorManager sensorManager, Sensor lightSensor, Handler handler) {
mContext = context;
@@ -41,6 +47,11 @@
mSensorManager = sensorManager;
mLightSensor = lightSensor;
mHandler = handler;
+
+ mLowBrightness = context.getResources().getInteger(
+ R.integer.config_doze_aod_brightness_low);
+ mHighBrightness = context.getResources().getInteger(
+ R.integer.config_doze_aod_brightness_high);
}
@Override
@@ -67,7 +78,17 @@
@Override
public void onSensorChanged(SensorEvent event) {
if (mRegistered) {
- mDozeService.setDozeScreenBrightness(Math.max(1, (int) event.values[0]));
+ mDozeService.setDozeScreenBrightness(computeBrightness((int) event.values[0]));
+ }
+ }
+
+ private int computeBrightness(int sensorValue) {
+ // The sensor reports 0 for off, 1 for low brightness and 2 for high brightness.
+ // We currently use DozeScreenState for screen off, so we treat off as low brightness.
+ if (sensorValue >= 2) {
+ return mHighBrightness;
+ } else {
+ return mLowBrightness;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java
index 4ff10e9..18fb423 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java
@@ -45,6 +45,7 @@
mFragmentHostManager.getFragmentManager().beginTransaction()
.replace(id, (Fragment) mExtension.get(), mTag)
.commit();
+ mExtension.clearItem(false);
}
@Override
@@ -57,6 +58,7 @@
} catch (ClassCastException e) {
Log.e(TAG, extension.getClass().getName() + " must be a Fragment", e);
}
+ mExtension.clearItem(true);
}
public static <T> void attachExtensonToFragment(View view, String tag, int id,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java b/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
index 5b3ec08..3d8f9ff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
@@ -16,12 +16,14 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.service.quicksettings.Tile;
import android.widget.ImageView;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QSTile.Icon;
import com.android.systemui.plugins.qs.QSTile.State;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.phone.SignalDrawable;
import java.util.Objects;
@@ -35,7 +37,8 @@
public CellTileView(Context context) {
super(context);
mSignalDrawable = new SignalDrawable(mContext);
- mSignalDrawable.setDarkIntensity(isDark(mContext));
+ mSignalDrawable.setColors(QSTileImpl.getColorForState(context, Tile.STATE_UNAVAILABLE),
+ QSTileImpl.getColorForState(context, Tile.STATE_ACTIVE));
mSignalDrawable.setIntrinsicSize(context.getResources().getDimensionPixelSize(
R.dimen.qs_tile_icon_size));
}
@@ -48,10 +51,6 @@
}
}
- private static int isDark(Context context) {
- return Utils.getColorAttr(context, android.R.attr.colorForeground) == 0xff000000 ? 1 : 0;
- }
-
public static class SignalIcon extends Icon {
private final int mState;
@@ -68,7 +67,8 @@
public Drawable getDrawable(Context context) {
//TODO: Not the optimal solution to create this drawable
SignalDrawable d = new SignalDrawable(context);
- d.setDarkIntensity(isDark(context));
+ d.setColors(QSTileImpl.getColorForState(context, Tile.STATE_UNAVAILABLE),
+ QSTileImpl.getColorForState(context, Tile.STATE_ACTIVE));
d.setLevel(getState());
return d;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
index a10aa54..c356148 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
@@ -33,11 +33,12 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
-import android.util.Log;
import android.util.FloatProperty;
public class SlashDrawable extends Drawable {
+ public static final float CORNER_RADIUS = 1f;
+
private final Path mPath = new Path();
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -61,6 +62,7 @@
private boolean mSlashed;
private Mode mTintMode;
private ColorStateList mTintList;
+ private boolean mAnimationEnabled = true;
public SlashDrawable(Drawable d) {
mDrawable = d;
@@ -97,6 +99,10 @@
invalidateSelf();
}
+ public void setAnimationEnabled(boolean enabled) {
+ mAnimationEnabled = enabled;
+ }
+
// Animate this value on change
private float mCurrentSlashLength;
private final FloatProperty mSlashLengthProp = new FloatProperty<SlashDrawable>("slashLength") {
@@ -119,12 +125,15 @@
final float end = mSlashed ? SLASH_HEIGHT / SCALE : 0f;
final float start = mSlashed ? 0f : SLASH_HEIGHT / SCALE;
- ObjectAnimator anim = ObjectAnimator.ofFloat(this, mSlashLengthProp, start, end);
- anim.addUpdateListener((ValueAnimator valueAnimator) -> {
+ if (mAnimationEnabled) {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, mSlashLengthProp, start, end);
+ anim.addUpdateListener((ValueAnimator valueAnimator) -> invalidateSelf());
+ anim.setDuration(QS_ANIM_LENGTH);
+ anim.start();
+ } else {
+ mCurrentSlashLength = end;
invalidateSelf();
- });
- anim.setDuration(QS_ANIM_LENGTH);
- anim.start();
+ }
}
@Override
@@ -133,8 +142,8 @@
Matrix m = new Matrix();
final int width = getBounds().width();
final int height = getBounds().height();
- final float radiusX = scale(1f, width);
- final float radiusY = scale(1f, height);
+ final float radiusX = scale(CORNER_RADIUS, width);
+ final float radiusY = scale(CORNER_RADIUS, height);
updateRect(
scale(LEFT, width),
scale(TOP, height),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 5ab3927..8074cb9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -98,10 +98,14 @@
d.setAutoMirrored(false);
d.setLayoutDirection(getLayoutDirection());
}
- iv.setImageDrawable(d);
- if (state.slash != null && iv instanceof SlashImageView) {
- ((SlashImageView) iv).setState(state.slash);
+
+ if (iv instanceof SlashImageView) {
+ ((SlashImageView) iv).setAnimationEnabled(shouldAnimate);
+ ((SlashImageView) iv).setState(state.slash, d);
+ } else {
+ iv.setImageDrawable(d);
}
+
iv.setTag(R.id.qs_icon_tag, state.icon);
iv.setTag(R.id.qs_slash_tag, state.slash);
iv.setPadding(0, padding, 0, padding);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
index 315a815..13912fe 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
@@ -14,8 +14,10 @@
package com.android.systemui.qs.tileimpl;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
import android.widget.ImageView;
import com.android.internal.annotations.VisibleForTesting;
@@ -26,6 +28,7 @@
@VisibleForTesting
protected SlashDrawable mSlash;
+ private boolean mAnimationEnabled = true;
public SlashImageView(Context context) {
super(context);
@@ -34,6 +37,7 @@
private void ensureSlashDrawable() {
if (mSlash == null) {
mSlash = new SlashDrawable(getDrawable());
+ mSlash.setAnimationEnabled(mAnimationEnabled);
super.setImageDrawable(mSlash);
}
}
@@ -46,13 +50,28 @@
} else if (mSlash == null) {
super.setImageDrawable(drawable);
} else {
+ mSlash.setAnimationEnabled(mAnimationEnabled);
mSlash.setDrawable(drawable);
}
}
- public void setState(SlashState slashState) {
+ public void setAnimationEnabled(boolean enabled) {
+ mAnimationEnabled = enabled;
+ }
+
+ private void setSlashState(@NonNull SlashState slashState) {
ensureSlashDrawable();
mSlash.setRotation(slashState.rotation);
mSlash.setSlashed(slashState.isSlashed);
}
+
+ public void setState(@Nullable SlashState state, @Nullable Drawable drawable) {
+ if (state != null) {
+ setImageDrawable(drawable);
+ setSlashState(state);
+ } else {
+ mSlash = null;
+ setImageDrawable(drawable);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
index e5aad033..ba92c45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
@@ -32,7 +32,7 @@
private final boolean mHasOverlappingRendering;
AnimationDrawable mAnim;
boolean mAttached;
- private boolean mAllowAnimation;
+ private boolean mAllowAnimation = true;
// Tracks the last image that was set, so that we don't refresh the image if it is exactly
// the same as the previous one. If this is a resid, we track that. If it's a drawable, we
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index a601028..e5f68ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -298,7 +298,8 @@
private void updateNotificationClipHeight(ExpandableNotificationRow row,
float notificationClipEnd) {
float viewEnd = row.getTranslationY() + row.getActualHeight();
- boolean isPinned = row.isPinned() || row.isHeadsUpAnimatingAway();
+ boolean isPinned = (row.isPinned() || row.isHeadsUpAnimatingAway())
+ && !mAmbientState.isDozingAndNotPulsing(row);
if (viewEnd > notificationClipEnd
&& (mAmbientState.isShadeExpanded() || !isPinned)) {
int clipBottomAmount = (int) (viewEnd - notificationClipEnd);
@@ -450,7 +451,7 @@
? fullTransitionAmount
: transitionAmount;
iconState.clampedAppearAmount = clampedAmount;
- float contentTransformationAmount = !row.isAboveShelf()
+ float contentTransformationAmount = !mAmbientState.isAboveShelf(row)
&& (isLastChild || iconState.translateContent)
? iconTransitionAmount
: 0.0f;
@@ -519,7 +520,7 @@
iconState.scaleY = 1.0f;
iconState.hidden = false;
}
- if (row.isAboveShelf() || (!row.isInShelf() && (isLastChild && row.areGutsExposed()
+ if (mAmbientState.isAboveShelf(row) || (!row.isInShelf() && (isLastChild && row.areGutsExposed()
|| row.getTranslationZ() > mAmbientState.getBaseZHeight()))) {
iconState.hidden = true;
}
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 652288d..e65bab6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -78,6 +78,7 @@
private AccelerateInterpolator mAccelerateInterpolator = new AccelerateInterpolator();
private int mClockBottom;
private float mDarkAmount;
+ private int mDozingStackPadding;
/**
* Refreshes the dimension values.
@@ -97,6 +98,7 @@
R.dimen.burn_in_prevention_offset_x);
mBurnInPreventionOffsetY = res.getDimensionPixelSize(
R.dimen.burn_in_prevention_offset_y);
+ mDozingStackPadding = res.getDimensionPixelSize(R.dimen.dozing_stack_padding);
}
public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight,
@@ -135,7 +137,7 @@
result.stackScrollerPadding = (int) interpolate(
result.stackScrollerPadding,
- mClockBottom + y,
+ mClockBottom + y + mDozingStackPadding,
mDarkAmount);
result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
index d537cda..15ef742 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
@@ -36,6 +36,7 @@
import com.android.settingslib.R;
import com.android.settingslib.Utils;
+import com.android.systemui.qs.SlashDrawable;
public class SignalDrawable extends Drawable {
@@ -198,6 +199,11 @@
return true;
}
+ public void setColors(int background, int foreground) {
+ mPaint.setColor(background);
+ mForegroundPaint.setColor(foreground);
+ }
+
public void setDarkIntensity(float darkIntensity) {
if (darkIntensity == mOldDarkIntensity) {
return;
@@ -333,10 +339,9 @@
mForegroundPath.reset();
mFullPath.op(mCutPath, Path.Op.DIFFERENCE);
} else if (mState == STATE_AIRPLANE) {
- // Airplane mode is slashed, full-signal
- mForegroundPath.set(mFullPath);
- mFullPath.reset();
- mSlash.draw((int) height, (int) width, canvas, mForegroundPaint);
+ // Airplane mode is slashed, fully drawn background
+ mForegroundPath.reset();
+ mSlash.draw((int) height, (int) width, canvas, mPaint);
} else if (mState != STATE_CARRIER_CHANGE) {
mForegroundPath.reset();
int sigWidth = Math.round(calcFit(mLevel / (mNumLevels - 1)) * (width - 2 * padding));
@@ -473,6 +478,7 @@
void draw(int height, int width, @NonNull Canvas canvas, Paint paint) {
Matrix m = new Matrix();
+ final float radius = scale(SlashDrawable.CORNER_RADIUS, width);
updateRect(
scale(LEFT, width),
scale(TOP, height),
@@ -481,7 +487,7 @@
mPath.reset();
// Draw the slash vertically
- mPath.addRect(mSlashRect, Direction.CW);
+ mPath.addRoundRect(mSlashRect, radius, radius, Direction.CW);
m.setRotate(ROTATION, width / 2, height / 2);
mPath.transform(m);
canvas.drawPath(mPath, paint);
@@ -491,7 +497,7 @@
mPath.transform(m);
m.setTranslate(mSlashRect.width(), 0);
mPath.transform(m);
- mPath.addRect(mSlashRect, Direction.CW);
+ mPath.addRoundRect(mSlashRect, radius, radius, Direction.CW);
m.setRotate(ROTATION, width / 2, height / 2);
mPath.transform(m);
canvas.clipOutPath(mPath);
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 8b3a60e..a11af51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4594,11 +4594,13 @@
try {
mOverlayManager.setEnabled("com.android.systemui.theme.lightwallpaper",
useDarkText, mCurrentUserId);
- mStatusBarWindowManager.setKeyguardDark(useDarkText);
} catch (RemoteException e) {
Log.w(TAG, "Can't change theme", e);
}
}
+
+ // Make sure we have the correct navbar/statusbar colors.
+ mStatusBarWindowManager.setKeyguardDark(useDarkText);
}
private void updateDozingState() {
@@ -5579,6 +5581,10 @@
private Set<String> mNonBlockablePkgs;
+ public boolean isDeviceInteractive() {
+ return mDeviceInteractive;
+ }
+
@Override // NotificationData.Environment
public boolean isDeviceProvisioned() {
return mDeviceProvisionedController.isDeviceProvisioned();
@@ -7254,6 +7260,9 @@
if (mAccessibilityManager.isTouchExplorationEnabled()) {
if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
return false;
+ } else if (mDozing) {
+ // We never want heads up when we are dozing.
+ return false;
} else {
// we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
return !mStatusBarKeyguardViewManager.isShowing()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
index 40e3806..ede8411 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
@@ -38,6 +38,13 @@
* (like configuration) may have changed.
*/
T reload();
+
+ /**
+ * Null out the cached item for the purpose of memory saving, should only be done
+ * when any other references are already gotten.
+ * @param isDestroyed
+ */
+ void clearItem(boolean isDestroyed);
}
interface ExtensionBuilder<T> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
index c2618cd..6df2051 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
@@ -26,6 +26,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.leak.LeakDetector;
import java.util.ArrayList;
import java.util.Collections;
@@ -146,7 +147,18 @@
return get();
}
+ @Override
+ public void clearItem(boolean isDestroyed) {
+ if (isDestroyed && mItem != null) {
+ Dependency.get(LeakDetector.class).trackGarbage(mItem);
+ }
+ mItem = null;
+ }
+
private void notifyChanged() {
+ if (mItem != null) {
+ Dependency.get(LeakDetector.class).trackGarbage(mItem);
+ }
mItem = null;
for (int i = 0; i < mProducers.size(); i++) {
final T item = mProducers.get(i).get();
@@ -169,7 +181,7 @@
}
public void addTunerFactory(TunerFactory<T> factory, String[] keys) {
- mProducers.add(new TunerItem(factory, factory.keys()));
+ mProducers.add(new TunerItem(factory, keys));
}
public void addUiMode(int uiMode, Supplier<T> mode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index ba1e7c2..4d8da44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -21,11 +21,15 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
+import java.util.Collection;
/**
* A global state to track all input states for the algorithm.
@@ -59,7 +63,7 @@
private boolean mPanelTracking;
private boolean mExpansionChanging;
private boolean mPanelFullWidth;
- private boolean mHasPulsingNotifications;
+ private Collection<HeadsUpManager.HeadsUpEntry> mPulsing;
private boolean mUnlockHintRunning;
private boolean mQsCustomizerShowing;
private int mIntrinsicPadding;
@@ -290,11 +294,23 @@
}
public boolean hasPulsingNotifications() {
- return mHasPulsingNotifications;
+ return mPulsing != null;
}
- public void setHasPulsingNotifications(boolean hasPulsing) {
- mHasPulsingNotifications = hasPulsing;
+ public void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> hasPulsing) {
+ mPulsing = hasPulsing;
+ }
+
+ public boolean isPulsing(NotificationData.Entry entry) {
+ if (mPulsing == null) {
+ return false;
+ }
+ for (HeadsUpManager.HeadsUpEntry e : mPulsing) {
+ if (e.entry == entry) {
+ return true;
+ }
+ }
+ return false;
}
public boolean isPanelTracking() {
@@ -332,4 +348,34 @@
public int getIntrinsicPadding() {
return mIntrinsicPadding;
}
+
+ /**
+ * Similar to the normal is above shelf logic but doesn't allow it to be above in AOD1.
+ *
+ * @param expandableView the view to check
+ */
+ public boolean isAboveShelf(ExpandableView expandableView) {
+ if (!(expandableView instanceof ExpandableNotificationRow)) {
+ return expandableView.isAboveShelf();
+ }
+ ExpandableNotificationRow row = (ExpandableNotificationRow) expandableView;
+ return row.isAboveShelf() && !isDozingAndNotPulsing(row);
+ }
+
+ /**
+ * @return whether a view is dozing and not pulsing right now
+ */
+ public boolean isDozingAndNotPulsing(ExpandableView view) {
+ if (view instanceof ExpandableNotificationRow) {
+ return isDozingAndNotPulsing((ExpandableNotificationRow) view);
+ }
+ return false;
+ }
+
+ /**
+ * @return whether a row is dozing and not pulsing right now
+ */
+ public boolean isDozingAndNotPulsing(ExpandableNotificationRow row) {
+ return isDark() && !isPulsing(row.getEntry());
+ }
}
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 74523e2..0097391 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -805,7 +805,7 @@
*/
private float getAppearStartPosition() {
if (mTrackingHeadsUp && mFirstVisibleBackgroundChild != null) {
- if (mFirstVisibleBackgroundChild.isAboveShelf()) {
+ if (mAmbientState.isAboveShelf(mFirstVisibleBackgroundChild)) {
// If we ever expanded beyond the first notification, it's allowed to merge into
// the shelf
return mFirstVisibleBackgroundChild.getPinnedHeadsUpHeight();
@@ -823,7 +823,8 @@
int notGoneChildCount = getNotGoneChildCount();
if (mEmptyShadeView.getVisibility() == GONE && notGoneChildCount != 0) {
int minNotificationsForShelf = 1;
- if (mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()) {
+ if (mTrackingHeadsUp
+ || (mHeadsUpManager.hasPinnedHeadsUp() && !mAmbientState.isDark())) {
appearPosition = mHeadsUpManager.getTopHeadsUpPinnedHeight();
minNotificationsForShelf = 2;
} else {
@@ -2008,12 +2009,7 @@
}
private boolean isPulsing(NotificationData.Entry entry) {
- for (HeadsUpManager.HeadsUpEntry e : mPulsing) {
- if (e.entry == entry) {
- return true;
- }
- }
- return false;
+ return mAmbientState.isPulsing(entry);
}
public boolean hasPulsingNotifications() {
@@ -4148,7 +4144,7 @@
return;
}
mPulsing = pulsing;
- mAmbientState.setHasPulsingNotifications(hasPulsingNotifications());
+ mAmbientState.setPulsing(pulsing);
updateNotificationAnimationStates();
updateContentHeight();
notifyHeightChangeListener(mShelf);
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 8235bc7..f4197a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -413,7 +413,7 @@
if (mIsExpanded) {
// Ensure that the heads up is always visible even when scrolled off
clampHunToTop(ambientState, row, childState);
- if (i == 0 && row.isAboveShelf()) {
+ if (i == 0 && ambientState.isAboveShelf(row)) {
// the first hun can't get off screen.
clampHunToMaxTranslation(ambientState, row, childState);
childState.hidden = false;
@@ -515,7 +515,7 @@
ExpandableViewState childViewState = resultState.getViewStateForView(child);
int zDistanceBetweenElements = ambientState.getZDistanceBetweenElements();
float baseZ = ambientState.getBaseZHeight();
- if (child.mustStayOnScreen()
+ if (child.mustStayOnScreen() && !ambientState.isDozingAndNotPulsing(child)
&& childViewState.yTranslation < ambientState.getTopPadding()
+ ambientState.getStackTranslation()) {
if (childrenOnTop != 0.0f) {
@@ -527,7 +527,7 @@
}
childViewState.zTranslation = baseZ
+ childrenOnTop * zDistanceBetweenElements;
- } else if (i == 0 && child.isAboveShelf()) {
+ } else if (i == 0 && ambientState.isAboveShelf(child)) {
// In case this is a new view that has never been measured before, we don't want to
// elevate if we are currently expanded more then the notification
int shelfHeight = ambientState.getShelf().getIntrinsicHeight();
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index ba9e60a..021f9c4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -21,6 +21,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import com.android.systemui.Dependency;
@@ -84,12 +85,15 @@
// TODO(b/35345376): Turn this back on for debuggable builds after known leak fixed.
private static final boolean ENABLED = Build.IS_DEBUGGABLE
&& SystemProperties.getBoolean("debug.enable_leak_reporting", false);
+ private static final String FORCE_ENABLE = "sysui_force_garbage_monitor";
private GarbageMonitor mGarbageMonitor;
@Override
public void start() {
- if (!ENABLED) {
+ boolean forceEnable = Settings.Secure.getInt(mContext.getContentResolver(),
+ FORCE_ENABLE, 0) != 0;
+ if (!ENABLED && !forceEnable) {
return;
}
mGarbageMonitor = Dependency.get(GarbageMonitor.class);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index eaad2f9..103eb6e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -48,8 +48,10 @@
import com.android.internal.annotations.GuardedBy;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.qs.tiles.DndTile;
+import com.android.systemui.statusbar.phone.StatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -89,11 +91,12 @@
private final W mWorker;
private final Context mContext;
private AudioManager mAudio;
+ protected StatusBar mStatusBar;
private final NotificationManager mNoMan;
private final SettingObserver mObserver;
private final Receiver mReceiver = new Receiver();
private final MediaSessions mMediaSessions;
- private final C mCallbacks = new C();
+ protected C mCallbacks = new C();
private final State mState = new State();
private final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
private final Vibrator mVibrator;
@@ -123,6 +126,7 @@
mReceiver.init();
mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
+ updateStatusBar();
boolean accessibilityVolumeStreamActive = context.getSystemService(
AccessibilityManager.class).isAccessibilityVolumeStreamActive();
@@ -326,8 +330,17 @@
return changed;
}
- private boolean onVolumeChangedW(int stream, int flags) {
- final boolean showUI = (flags & AudioManager.FLAG_SHOW_UI) != 0;
+ private void updateStatusBar() {
+ if (mStatusBar == null) {
+ mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
+ }
+ }
+
+ boolean onVolumeChangedW(int stream, int flags) {
+ updateStatusBar();
+
+ final boolean showUI = (mStatusBar != null && mStatusBar.isDeviceInteractive()) &&
+ ((flags & AudioManager.FLAG_SHOW_UI) != 0);
final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
final boolean showSilentHint = (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0;
@@ -638,7 +651,7 @@
}
}
- private final class C implements Callbacks {
+ class C implements Callbacks {
private final HashMap<Callbacks, Handler> mCallbackMap = new HashMap<>();
public void add(Callbacks callback, Handler handler) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 32fd3e0..7e9c865 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -180,7 +180,13 @@
@Override
public void destroy() {
+ mAccessibility.destroy();
mController.removeCallback(mControllerCallbackH);
+ if (mZenFooter != null) {
+ mZenFooter.cleanup();
+ }
+ Dependency.get(TunerService.class).removeTunable(this);
+ mHandler.removeCallbacksAndMessages(null);
}
private void initDialog() {
@@ -1241,16 +1247,14 @@
}
});
mDialogView.setAccessibilityDelegate(this);
- mAccessibilityMgr.addAccessibilityStateChangeListener(
- new AccessibilityStateChangeListener() {
- @Override
- public void onAccessibilityStateChanged(boolean enabled) {
- updateFeedbackEnabled();
- }
- });
+ mAccessibilityMgr.addAccessibilityStateChangeListener(mListener);
updateFeedbackEnabled();
}
+ public void destroy() {
+ mAccessibilityMgr.removeAccessibilityStateChangeListener(mListener);
+ }
+
@Override
public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
AccessibilityEvent event) {
@@ -1273,6 +1277,9 @@
}
return false;
}
+
+ private final AccessibilityStateChangeListener mListener =
+ enabled -> updateFeedbackEnabled();
}
private static class VolumeRow {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
index a81188a..d0f0bfd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
@@ -48,14 +48,13 @@
@Test
public void getColors_usesGreyIfWallpaperNotVisible() {
- ColorExtractor.GradientColors fallbackColors = new ColorExtractor.GradientColors();
- fallbackColors.setMainColor(ColorExtractor.FALLBACK_COLOR);
- fallbackColors.setSecondaryColor(ColorExtractor.FALLBACK_COLOR);
-
- SysuiColorExtractor extractor = new SysuiColorExtractor(getContext(), new Tonal(), false);
+ SysuiColorExtractor extractor = new SysuiColorExtractor(getContext(),
+ new Tonal(getContext()), false);
simulateEvent(extractor);
extractor.setWallpaperVisible(false);
+ ColorExtractor.GradientColors fallbackColors = extractor.getFallbackColors();
+
for (int which : sWhich) {
for (int type : sTypes) {
assertEquals("Not using fallback!", extractor.getColors(which, type),
@@ -76,7 +75,6 @@
outGradientColorsNormal.set(colors);
outGradientColorsDark.set(colors);
outGradientColorsExtraDark.set(colors);
- return true;
}, false);
simulateEvent(extractor);
extractor.setWallpaperVisible(true);
@@ -91,7 +89,7 @@
private void simulateEvent(SysuiColorExtractor extractor) {
// Let's fake a color event
- extractor.onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK), null, null, 0),
+ extractor.onColorsChanged(new WallpaperColors(Color.valueOf(Color.GREEN), null, null, 0),
WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK);
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 514dc8b..fe3221a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -38,11 +38,13 @@
import com.android.systemui.utils.hardware.FakeSensorManager;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
+@Ignore
public class DozeScreenBrightnessTest extends SysuiTestCase {
DozeServiceFake mServiceFake;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java
index aef584f..9fe3e10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java
@@ -38,26 +38,39 @@
private TestableSlashImageView mSlashView;
@Test
- public void testSetSlashStateCreatesSlashDrawable() {
+ public void testSetNonNullSlashStateCreatesSlashDrawable() {
SlashState mockState = mock(SlashState.class);
Drawable mockDrawable = mock(Drawable.class);
mSlashView = new TestableSlashImageView(mContext);
assertTrue(mSlashView.getSlashDrawable() == null);
- mSlashView.setImageDrawable(mockDrawable);
- mSlashView.setState(mockState);
+ mSlashView.setState(mockState, mockDrawable);
assertTrue(mSlashView.getSlashDrawable() != null);
}
@Test
+ public void testSetNullSlashStateRemovesSlashDrawable() {
+ SlashState mockState = mock(SlashState.class);
+ Drawable mockDrawable = mock(Drawable.class);
+ mSlashView = new TestableSlashImageView(mContext);
+ mSlashView.setState(mockState, mockDrawable);
+
+ assertTrue(mSlashView.getSlashDrawable() != null);
+
+ mSlashView.setState(null, mockDrawable);
+
+ assertTrue(mSlashView.getSlashDrawable() == null);
+ }
+
+ @Test
public void testSetNullDrawableRemovesSlashDrawable() {
SlashState mockState = mock(SlashState.class);
Drawable mockDrawable = mock(Drawable.class);
mSlashView = new TestableSlashImageView(mContext);
mSlashView.setImageDrawable(mockDrawable);
- mSlashView.setState(mockState);
+ mSlashView.setState(mockState, mockDrawable);
mSlashView.setImageDrawable(null);
assertTrue(mSlashView.getSlashDrawable() == null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java
index daf7547..586a424 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java
@@ -100,6 +100,11 @@
}
@Override
+ public void clearItem(boolean isDestroyed) {
+
+ }
+
+ @Override
public Context getContext() {
return null;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
new file mode 100644
index 0000000..8060f5b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.support.test.filters.SmallTest;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@SmallTest
+public class VolumeDialogControllerImplTest extends SysuiTestCase {
+
+ TestableVolumeDialogControllerImpl mVolumeController;
+ VolumeDialogControllerImpl.C mCallback;
+ StatusBar mStatusBar;
+
+ @Before
+ public void setup() throws Exception {
+ mCallback = mock(VolumeDialogControllerImpl.C.class);
+ mStatusBar = mock(StatusBar.class);
+ mVolumeController = new TestableVolumeDialogControllerImpl(mContext, mCallback, mStatusBar);
+ }
+
+ @Test
+ public void testVolumeChangeW_deviceNotInteractiveAOD() {
+ when(mStatusBar.isDeviceInteractive()).thenReturn(false);
+ mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
+ verify(mCallback, never()).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
+ }
+
+ @Test
+ public void testVolumeChangeW_deviceInteractive() {
+ when(mStatusBar.isDeviceInteractive()).thenReturn(true);
+ mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
+ verify(mCallback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
+ }
+
+ static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
+ public TestableVolumeDialogControllerImpl(Context context, C callback, StatusBar s) {
+ super(context);
+ mCallbacks = callback;
+ mStatusBar = s;
+ }
+ }
+
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 78d593e..d6ca23f 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -138,6 +138,18 @@
REASON_TIMEOUT = 19;
}
+ // Subtypes of camera events for ACTION_CAMERA_EVENT
+ enum CameraEvent {
+ // A back-facing camera was used
+ CAMERA_BACK_USED = 0;
+
+ // A front-facing camera was used
+ CAMERA_FRONT_USED = 1;
+
+ // An external camera was used
+ CAMERA_EXTERNAL_USED = 2;
+ }
+
// Known visual elements: views or controls.
enum View {
// Unknown view
@@ -4196,6 +4208,12 @@
// OS: O DR
DIALOG_BLUETOOTH_PAIRED_DEVICE_FORGET = 1031;
+ // An event from the camera service
+ // CATEGORY: OTHER
+ // SUBTYPE: CameraEvent
+ // OS: O DR
+ ACTION_CAMERA_EVENT = 1032;
+
// ---- End O-DR1 Constants, all O-DR1 constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 4a7eef9..abfc31e 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -4871,6 +4871,7 @@
final int N = mPackages.size();
final byte[] buffer = new byte[8192];
for (int i = 0; i < N; i++) {
+ mBackupRunner = null;
PackageInfo currentPackage = mPackages.get(i);
String packageName = currentPackage.packageName;
if (DEBUG) {
@@ -5054,7 +5055,13 @@
}
EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE, packageName,
"transport rejected");
- // Do nothing, clean up, and continue looping.
+ // This failure state can come either a-priori from the transport, or
+ // from the preflight pass. If we got as far as preflight, we now need
+ // to tear down the target process.
+ if (mBackupRunner != null) {
+ tearDownAgentAndKill(currentPackage.applicationInfo);
+ }
+ // ... and continue looping.
} else if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
sendBackupOnPackageResult(mBackupObserver, packageName,
BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
@@ -5063,6 +5070,7 @@
EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED,
packageName);
}
+ tearDownAgentAndKill(currentPackage.applicationInfo);
// Do nothing, clean up, and continue looping.
} else if (backupPackageStatus == BackupTransport.AGENT_ERROR) {
sendBackupOnPackageResult(mBackupObserver, packageName,
@@ -5086,6 +5094,7 @@
EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE);
// Abort entire backup pass.
backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
+ tearDownAgentAndKill(currentPackage.applicationInfo);
return;
} else {
// Success!
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 8ea334d..7959e39 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.SHUTDOWN;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
@@ -55,6 +56,7 @@
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.INetworkManagementEventObserver;
+import android.net.ITetheringStatsProvider;
import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -225,6 +227,10 @@
private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
+ @GuardedBy("mTetheringStatsProviders")
+ private final HashMap<ITetheringStatsProvider, String>
+ mTetheringStatsProviders = Maps.newHashMap();
+
/**
* If both locks need to be held, then they should be obtained in the order:
* first {@link #mQuotaLock} and then {@link #mRulesLock}.
@@ -331,6 +337,10 @@
Watchdog.getInstance().addMonitor(this);
LocalServices.addService(NetworkManagementInternal.class, new LocalService());
+
+ synchronized (mTetheringStatsProviders) {
+ mTetheringStatsProviders.put(new NetdTetheringStatsProvider(), "netd");
+ }
}
@VisibleForTesting
@@ -520,6 +530,23 @@
}
}
+ @Override
+ public void registerTetheringStatsProvider(ITetheringStatsProvider provider, String name) {
+ mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+ Preconditions.checkNotNull(provider);
+ synchronized(mTetheringStatsProviders) {
+ mTetheringStatsProviders.put(provider, name);
+ }
+ }
+
+ @Override
+ public void unregisterTetheringStatsProvider(ITetheringStatsProvider provider) {
+ mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+ synchronized(mTetheringStatsProviders) {
+ mTetheringStatsProviders.remove(provider);
+ }
+ }
+
// Sync the state of the given chain with the native daemon.
private void syncFirewallChainLocked(int chain, String name) {
SparseIntArray rules;
@@ -1789,14 +1816,16 @@
}
}
- @Override
- public NetworkStats getNetworkStatsTethering() {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
- try {
- final NativeDaemonEvent[] events = mConnector.executeForList(
- "bandwidth", "gettetherstats");
+ private class NetdTetheringStatsProvider extends ITetheringStatsProvider.Stub {
+ @Override
+ public NetworkStats getTetherStats() {
+ final NativeDaemonEvent[] events;
+ try {
+ events = mConnector.executeForList("bandwidth", "gettetherstats");
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
for (NativeDaemonEvent event : events) {
if (event.getCode() != TetheringStatsListResult) continue;
@@ -1822,8 +1851,24 @@
throw new IllegalStateException("problem parsing tethering stats: " + event);
}
}
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ return stats;
+ }
+ }
+
+ @Override
+ public NetworkStats getNetworkStatsTethering() {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
+ synchronized (mTetheringStatsProviders) {
+ for (ITetheringStatsProvider provider: mTetheringStatsProviders.keySet()) {
+ try {
+ stats.combineAllValues(provider.getTetherStats());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Problem reading tethering stats from " +
+ mTetheringStatsProviders.get(provider) + ": " + e);
+ }
+ }
}
return stats;
}
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 72ff606..581914d 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.os.SystemClock;
import android.os.Trace;
import android.util.Slog;
@@ -118,14 +119,14 @@
// Register it.
mServices.add(service);
// Start it.
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onStart");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
/**
@@ -146,7 +147,7 @@
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, service.getClass().getName());
try {
service.onBootPhase(mCurrentPhase);
@@ -156,7 +157,7 @@
+ ": onBootPhase threw an exception during phase "
+ mCurrentPhase, ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onBootPhase");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
} finally {
@@ -178,14 +179,14 @@
final SystemService service = mServices.get(i);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onStartUser "
+ service.getClass().getName());
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
try {
service.onStartUser(userHandle);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting start of user " + userHandle
+ " to service " + service.getClass().getName(), ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onStartUser ");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStartUser ");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
@@ -197,14 +198,14 @@
final SystemService service = mServices.get(i);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onUnlockUser "
+ service.getClass().getName());
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
try {
service.onUnlockUser(userHandle);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting unlock of user " + userHandle
+ " to service " + service.getClass().getName(), ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onUnlockUser ");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onUnlockUser ");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
@@ -216,14 +217,14 @@
final SystemService service = mServices.get(i);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onSwitchUser "
+ service.getClass().getName());
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
try {
service.onSwitchUser(userHandle);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting switch of user " + userHandle
+ " to service " + service.getClass().getName(), ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onSwitchUser");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onSwitchUser");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
@@ -235,14 +236,14 @@
final SystemService service = mServices.get(i);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onStopUser "
+ service.getClass().getName());
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
try {
service.onStopUser(userHandle);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting stop of user " + userHandle
+ " to service " + service.getClass().getName(), ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onStopUser");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStopUser");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
@@ -254,14 +255,14 @@
final SystemService service = mServices.get(i);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onCleanupUser "
+ service.getClass().getName());
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
try {
service.onCleanupUser(userHandle);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting cleanup of user " + userHandle
+ " to service " + service.getClass().getName(), ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onCleanupUser");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onCleanupUser");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index b18fa32..aceedf1 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -85,8 +85,9 @@
"android.hardware.bluetooth@1.0::IBluetoothHci",
"android.hardware.camera.provider@2.4::ICameraProvider",
"android.hardware.graphics.composer@2.1::IComposer",
- "android.hardware.vr@1.0::IVr",
- "android.hardware.media.omx@1.0::IOmx"
+ "android.hardware.media.omx@1.0::IOmx",
+ "android.hardware.sensors@1.0::ISensors",
+ "android.hardware.vr@1.0::IVr"
);
static Watchdog sWatchdog;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f106ca0..75467f5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12460,10 +12460,10 @@
switch (mWakefulness) {
case PowerManagerInternal.WAKEFULNESS_AWAKE:
case PowerManagerInternal.WAKEFULNESS_DREAMING:
- case PowerManagerInternal.WAKEFULNESS_DOZING:
// Pause applications whenever the lock screen is shown or any sleep
// tokens have been acquired.
return mKeyguardController.isKeyguardShowing() || !mSleepTokens.isEmpty();
+ case PowerManagerInternal.WAKEFULNESS_DOZING:
case PowerManagerInternal.WAKEFULNESS_ASLEEP:
default:
// If we're asleep then pause applications unconditionally.
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 1a7bba0..7a00a54 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -42,6 +42,7 @@
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NO_HISTORY;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
+import static android.content.pm.ActivityInfo.CONFIG_ROTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
@@ -2596,6 +2597,10 @@
changes &= ~CONFIG_SMALLEST_SCREEN_SIZE;
}
}
+ // We don't want rotation to cause relaunches.
+ if ((changes & CONFIG_ROTATION) != 0) {
+ changes &= ~CONFIG_ROTATION;
+ }
return changes;
}
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 82b2566..3133a51 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -21,6 +21,7 @@
import android.content.IntentFilter;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceProxy;
+import android.metrics.LogMaker;
import android.nfc.INfcAdapter;
import android.os.Binder;
import android.os.Handler;
@@ -28,15 +29,23 @@
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserManager;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
import java.util.Set;
/**
@@ -65,6 +74,9 @@
private static final int RETRY_DELAY_TIME = 20; //ms
+ // Maximum entries to keep in usage history before dumping out
+ private static final int MAX_USAGE_HISTORY = 100;
+
private final Context mContext;
private final ServiceThread mHandlerThread;
private final Handler mHandler;
@@ -76,14 +88,52 @@
private ICameraService mCameraServiceRaw;
- private final ArraySet<String> mActiveCameraIds = new ArraySet<>();
-
+ private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>();
+ private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>();
+ private final MetricsLogger mLogger = new MetricsLogger();
private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc";
private static final String NFC_SERVICE_BINDER_NAME = "nfc";
private static final IBinder nfcInterfaceToken = new Binder();
private final boolean mNotifyNfc;
- private int mActiveCameraCount = 0;
+
+ /**
+ * Structure to track camera usage
+ */
+ private static class CameraUsageEvent {
+ public final int mCameraFacing;
+ public final String mClientName;
+
+ private boolean mCompleted;
+ private long mDurationOrStartTimeMs; // Either start time, or duration once completed
+
+ public CameraUsageEvent(int facing, String clientName) {
+ mCameraFacing = facing;
+ mClientName = clientName;
+ mDurationOrStartTimeMs = SystemClock.elapsedRealtime();
+ mCompleted = false;
+ }
+
+ public void markCompleted() {
+ if (mCompleted) {
+ return;
+ }
+ mCompleted = true;
+ mDurationOrStartTimeMs = SystemClock.elapsedRealtime() - mDurationOrStartTimeMs;
+ if (CameraServiceProxy.DEBUG) {
+ Slog.v(TAG, "A camera facing " + cameraFacingToString(mCameraFacing) +
+ " was in use by " + mClientName + " for " +
+ mDurationOrStartTimeMs + " ms");
+ }
+ }
+
+ /**
+ * Return duration of camera usage event, or 0 if the event is not done
+ */
+ public long getDuration() {
+ return mCompleted ? mDurationOrStartTimeMs : 0;
+ }
+ }
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
@@ -120,10 +170,11 @@
public void notifyCameraState(String cameraId, int newCameraState, int facing,
String clientName) {
String state = cameraStateToString(newCameraState);
- if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facing + " state now " +
+ String facingStr = cameraFacingToString(facing);
+ if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facingStr + " state now " +
state + " for client " + clientName);
- updateActivityCount(cameraId, newCameraState);
+ updateActivityCount(cameraId, newCameraState, facing, clientName);
}
};
@@ -169,6 +220,9 @@
mContext.registerReceiver(mIntentReceiver, filter);
publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy);
+ publishLocalService(CameraServiceProxy.class, this);
+
+ CameraStatsJobService.schedule(mContext);
}
@Override
@@ -198,8 +252,8 @@
mCameraServiceRaw = null;
// All cameras reset to idle on camera service death
- boolean wasEmpty = mActiveCameraIds.isEmpty();
- mActiveCameraIds.clear();
+ boolean wasEmpty = mActiveCameraUsage.isEmpty();
+ mActiveCameraUsage.clear();
if ( mNotifyNfc && !wasEmpty ) {
notifyNfcService(/*enablePolling*/ true);
@@ -207,6 +261,46 @@
}
}
+ /**
+ * Dump camera usage events to log.
+ * Package-private
+ */
+ void dumpUsageEvents() {
+ synchronized(mLock) {
+ // Randomize order of events so that it's not meaningful
+ Collections.shuffle(mCameraUsageHistory);
+ for (CameraUsageEvent e : mCameraUsageHistory) {
+ if (DEBUG) {
+ Slog.v(TAG, "Camera: " + e.mClientName + " used a camera facing " +
+ cameraFacingToString(e.mCameraFacing) + " for " +
+ e.getDuration() + " ms");
+ }
+ int subtype = 0;
+ switch(e.mCameraFacing) {
+ case ICameraServiceProxy.CAMERA_FACING_BACK:
+ subtype = MetricsEvent.CAMERA_BACK_USED;
+ break;
+ case ICameraServiceProxy.CAMERA_FACING_FRONT:
+ subtype = MetricsEvent.CAMERA_FRONT_USED;
+ break;
+ case ICameraServiceProxy.CAMERA_FACING_EXTERNAL:
+ subtype = MetricsEvent.CAMERA_EXTERNAL_USED;
+ break;
+ default:
+ continue;
+ }
+ LogMaker l = new LogMaker(MetricsEvent.ACTION_CAMERA_EVENT)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .setSubtype(subtype)
+ .setLatency(e.getDuration())
+ .setPackageName(e.mClientName);
+ mLogger.write(l);
+ }
+ mCameraUsageHistory.clear();
+ }
+ CameraStatsJobService.schedule(mContext);
+ }
+
private void switchUserLocked(int userHandle) {
Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle);
mLastUser = userHandle;
@@ -274,21 +368,35 @@
return true;
}
- private void updateActivityCount(String cameraId, int newCameraState) {
+ private void updateActivityCount(String cameraId, int newCameraState, int facing, String clientName) {
synchronized(mLock) {
- boolean wasEmpty = mActiveCameraIds.isEmpty();
+ // Update active camera list and notify NFC if necessary
+ boolean wasEmpty = mActiveCameraUsage.isEmpty();
switch (newCameraState) {
case ICameraServiceProxy.CAMERA_STATE_OPEN:
break;
case ICameraServiceProxy.CAMERA_STATE_ACTIVE:
- mActiveCameraIds.add(cameraId);
+ CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName);
+ CameraUsageEvent oldEvent = mActiveCameraUsage.put(cameraId, newEvent);
+ if (oldEvent != null) {
+ Slog.w(TAG, "Camera " + cameraId + " was already marked as active");
+ oldEvent.markCompleted();
+ mCameraUsageHistory.add(oldEvent);
+ }
break;
case ICameraServiceProxy.CAMERA_STATE_IDLE:
case ICameraServiceProxy.CAMERA_STATE_CLOSED:
- mActiveCameraIds.remove(cameraId);
+ CameraUsageEvent doneEvent = mActiveCameraUsage.remove(cameraId);
+ if (doneEvent != null) {
+ doneEvent.markCompleted();
+ mCameraUsageHistory.add(doneEvent);
+ if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) {
+ dumpUsageEvents();
+ }
+ }
break;
}
- boolean isEmpty = mActiveCameraIds.isEmpty();
+ boolean isEmpty = mActiveCameraUsage.isEmpty();
if ( mNotifyNfc && (wasEmpty != isEmpty) ) {
notifyNfcService(isEmpty);
}
@@ -332,4 +440,15 @@
}
return "CAMERA_STATE_UNKNOWN";
}
+
+ private static String cameraFacingToString(int cameraFacing) {
+ switch (cameraFacing) {
+ case ICameraServiceProxy.CAMERA_FACING_BACK: return "CAMERA_FACING_BACK";
+ case ICameraServiceProxy.CAMERA_FACING_FRONT: return "CAMERA_FACING_FRONT";
+ case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: return "CAMERA_FACING_EXTERNAL";
+ default: break;
+ }
+ return "CAMERA_FACING_UNKNOWN";
+ }
+
}
diff --git a/services/core/java/com/android/server/camera/CameraStatsJobService.java b/services/core/java/com/android/server/camera/CameraStatsJobService.java
new file mode 100644
index 0000000..b8a6846
--- /dev/null
+++ b/services/core/java/com/android/server/camera/CameraStatsJobService.java
@@ -0,0 +1,77 @@
+/*
+ * 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/LICENSE2.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.camera;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.util.Slog;
+
+import java.util.concurrent.TimeUnit;
+
+import com.android.server.LocalServices;
+
+/**
+ * A JobService to periodically collect camera usage stats.
+ */
+public class CameraStatsJobService extends JobService {
+ private static final String TAG = "CameraStatsJobService";
+
+ // Must be unique within UID (system service)
+ private static final int CAMERA_REPORTING_JOB_ID = 0xCA3E7A;
+
+ private static ComponentName sCameraStatsJobServiceName = new ComponentName(
+ "android",
+ CameraStatsJobService.class.getName());
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ CameraServiceProxy serviceProxy = LocalServices.getService(CameraServiceProxy.class);
+ if (serviceProxy == null) {
+ Slog.w(TAG, "Can't collect camera usage stats - no camera service proxy found");
+ return false;
+ }
+
+ serviceProxy.dumpUsageEvents();
+ return false;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ // All work is done in onStartJob, so nothing to stop here
+ return false;
+ }
+
+ public static void schedule(Context context) {
+
+ JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ if (js == null) {
+ Slog.e(TAG, "Can't collect camera usage stats - no Job Scheduler");
+ return;
+ }
+ js.schedule(new JobInfo.Builder(CAMERA_REPORTING_JOB_ID, sCameraStatsJobServiceName)
+ .setMinimumLatency(TimeUnit.DAYS.toMillis(1))
+ .setRequiresDeviceIdle(true)
+ .build());
+
+ }
+
+}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 1fb944f..b0be8f7 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -214,7 +214,7 @@
final Handler smHandler = mTetherMasterSM.getHandler();
mOffloadController = new OffloadController(smHandler,
deps.getOffloadHardwareInterface(smHandler, mLog),
- mContext.getContentResolver(),
+ mContext.getContentResolver(), mNMService,
mLog);
mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
@@ -1759,6 +1759,11 @@
pw.decreaseIndent();
}
+ pw.println("Hardware offload:");
+ pw.increaseIndent();
+ mOffloadController.dump(pw);
+ pw.decreaseIndent();
+
pw.println("Log:");
pw.increaseIndent();
if (argsContain(args, SHORT_ARG)) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index b473867..1a5ff77 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -16,24 +16,38 @@
package com.android.server.connectivity.tethering;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.TrafficStats.UID_TETHERING;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
import android.content.ContentResolver;
+import android.net.ITetheringStatsProvider;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkStats;
import android.net.RouteInfo;
import android.net.util.SharedLog;
import android.os.Handler;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.SystemClock;
import android.provider.Settings;
+import android.text.TextUtils;
+
+import com.android.internal.util.IndentingPrintWriter;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* A class to encapsulate the business logic of programming the tethering
@@ -44,6 +58,8 @@
public class OffloadController {
private static final String TAG = OffloadController.class.getSimpleName();
+ private static final int STATS_FETCH_TIMEOUT_MS = 1000;
+
private final Handler mHandler;
private final OffloadHardwareInterface mHwInterface;
private final ContentResolver mContentResolver;
@@ -59,14 +75,25 @@
// prefixes representing only the locally-assigned IP addresses.
private Set<String> mLastLocalPrefixStrs;
+ // Maps upstream interface names to offloaded traffic statistics.
+ private HashMap<String, OffloadHardwareInterface.ForwardedStats>
+ mForwardedStats = new HashMap<>();
+
public OffloadController(Handler h, OffloadHardwareInterface hwi,
- ContentResolver contentResolver, SharedLog log) {
+ ContentResolver contentResolver, INetworkManagementService nms, SharedLog log) {
mHandler = h;
mHwInterface = hwi;
mContentResolver = contentResolver;
mLog = log.forSubComponent(TAG);
mExemptPrefixes = new HashSet<>();
mLastLocalPrefixStrs = new HashSet<>();
+
+ try {
+ nms.registerTetheringStatsProvider(
+ new OffloadTetheringStatsProvider(), getClass().getSimpleName());
+ } catch (RemoteException e) {
+ mLog.e("Cannot register offload stats provider: " + e);
+ }
}
public void start() {
@@ -138,6 +165,7 @@
public void stop() {
final boolean wasStarted = started();
+ updateStatsForCurrentUpstream();
mUpstreamLinkProperties = null;
mHwInterface.stopOffloadControl();
mControlInitialized = false;
@@ -145,16 +173,76 @@
if (wasStarted) mLog.log("tethering offload stopped");
}
+ private class OffloadTetheringStatsProvider extends ITetheringStatsProvider.Stub {
+ @Override
+ public NetworkStats getTetherStats() {
+ NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
+ CountDownLatch latch = new CountDownLatch(1);
+
+ mHandler.post(() -> {
+ try {
+ NetworkStats.Entry entry = new NetworkStats.Entry();
+ entry.set = SET_DEFAULT;
+ entry.tag = TAG_NONE;
+ entry.uid = UID_TETHERING;
+
+ updateStatsForCurrentUpstream();
+
+ for (String iface : mForwardedStats.keySet()) {
+ entry.iface = iface;
+ entry.rxBytes = mForwardedStats.get(iface).rxBytes;
+ entry.txBytes = mForwardedStats.get(iface).txBytes;
+ stats.addValues(entry);
+ }
+ } finally {
+ latch.countDown();
+ }
+ });
+
+ try {
+ latch.await(STATS_FETCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ mLog.e("Tethering stats fetch timed out after " + STATS_FETCH_TIMEOUT_MS + "ms");
+ }
+
+ return stats;
+ }
+ }
+
+ private void maybeUpdateStats(String iface) {
+ if (TextUtils.isEmpty(iface)) {
+ return;
+ }
+
+ if (!mForwardedStats.containsKey(iface)) {
+ mForwardedStats.put(iface, new OffloadHardwareInterface.ForwardedStats());
+ }
+ mForwardedStats.get(iface).add(mHwInterface.getForwardedStats(iface));
+ }
+
+ private void updateStatsForCurrentUpstream() {
+ if (mUpstreamLinkProperties != null) {
+ maybeUpdateStats(mUpstreamLinkProperties.getInterfaceName());
+ }
+ }
+
public void setUpstreamLinkProperties(LinkProperties lp) {
if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return;
+ String prevUpstream = (mUpstreamLinkProperties != null) ?
+ mUpstreamLinkProperties.getInterfaceName() : null;
+
mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null;
+
// TODO: examine return code and decide what to do if programming
// upstream parameters fails (probably just wait for a subsequent
// onOffloadEvent() callback to tell us offload is available again and
// then reapply all state).
computeAndPushLocalPrefixes();
pushUpstreamParameters();
+
+ // Update stats after we've told the hardware to change routing so we don't miss packets.
+ maybeUpdateStats(prevUpstream);
}
public void setLocalPrefixes(Set<IpPrefix> localPrefixes) {
@@ -262,4 +350,16 @@
for (IpPrefix pfx : prefixSet) localPrefixStrs.add(pfx.toString());
return localPrefixStrs;
}
+
+ public void dump(IndentingPrintWriter pw) {
+ if (isOffloadDisabled()) {
+ pw.println("Offload disabled");
+ return;
+ }
+ pw.println("Offload HALs " + (started() ? "started" : "not started"));
+ LinkProperties lp = mUpstreamLinkProperties;
+ String upstream = (lp != null) ? lp.getInterfaceName() : null;
+ pw.println("Current upstream: " + upstream);
+ pw.println("Exempt prefixes: " + mLastLocalPrefixStrs);
+ }
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 601dd94..83bb17e 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -2516,6 +2516,7 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
StringBuilder s = new StringBuilder();
+ s.append(" mStarted=").append(mStarted).append('\n');
s.append(" mFixInterval=").append(mFixInterval).append('\n');
s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 57605bb..a7eb2c6 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -520,7 +520,8 @@
}
}
- private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
+ @VisibleForTesting
+ final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
@Override
public void onSetDisabled(int status) {
@@ -1012,6 +1013,25 @@
}
@VisibleForTesting
+ int getNotificationRecordCount() {
+ synchronized (mNotificationLock) {
+ int count = mNotificationList.size() + mNotificationsByKey.size()
+ + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
+ // subtract duplicates
+ for (NotificationRecord posted : mNotificationList) {
+ if (mNotificationsByKey.containsKey(posted.getKey())) {
+ count--;
+ }
+ if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
+ count --;
+ }
+ }
+
+ return count;
+ }
+ }
+
+ @VisibleForTesting
void addNotification(NotificationRecord r) {
mNotificationList.add(r);
mNotificationsByKey.put(r.sbn.getKey(), r);
@@ -4553,6 +4573,7 @@
canceledNotifications = new ArrayList<>();
}
notificationList.remove(i);
+ mNotificationsByKey.remove(r.getKey());
canceledNotifications.add(r);
cancelNotificationLocked(r, sendDelete, reason, wasPosted);
}
@@ -4662,6 +4683,7 @@
EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
childSbn.getTag(), userId, 0, 0, reason, listenerName);
notificationList.remove(i);
+ mNotificationsByKey.remove(childR.getKey());
cancelNotificationLocked(childR, sendDelete, reason, wasPosted);
}
}
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index cb8416b..45e9cc7 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -73,11 +73,13 @@
ret = (sHal == nullptr) ? NullptrStatus<R>()
: (*sHal.*fn)(std::forward<Args1>(args1)...);
- if (!ret.isOk()) {
- ALOGE("Failed to issue command to vibrator HAL. Retrying.");
- // Restoring connection to the HAL.
- sHal = I::tryGetService();
+ if (ret.isOk()) {
+ break;
}
+
+ ALOGE("Failed to issue command to vibrator HAL. Retrying.");
+ // Restoring connection to the HAL.
+ sHal = I::tryGetService();
}
return ret;
}
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 37ae782..2dfd8b9 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -59,7 +59,7 @@
static bool wakeup_init = false;
static sem_t wakeup_sem;
-extern sp<IPower> gPowerHal;
+extern sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0;
extern std::mutex gPowerHalMutex;
extern bool getPowerHal();
@@ -203,7 +203,7 @@
return -1;
}
- Return<void> ret = gPowerHal->getPlatformLowPowerStats(
+ Return<void> ret = gPowerHalV1_0->getPlatformLowPowerStats(
[&offset, &remaining, &total_added](hidl_vec<PowerStatePlatformSleepState> states,
Status status) {
if (status != Status::SUCCESS)
@@ -257,7 +257,7 @@
if (!ret.isOk()) {
ALOGE("getPlatformLowPowerStats() failed: power HAL service not available");
- gPowerHal = nullptr;
+ gPowerHalV1_0 = nullptr;
return -1;
}
}
@@ -288,7 +288,7 @@
}
//Trying to cast to 1.1, this will succeed only for devices supporting 1.1
- gPowerHal_1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHal);
+ gPowerHal_1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
if (gPowerHal_1_1 == nullptr) {
//This device does not support IPower@1.1, exiting gracefully
return 0;
@@ -351,7 +351,7 @@
if (!ret.isOk()) {
ALOGE("getSubsystemLowPowerStats() failed: power HAL service not available");
- gPowerHal = nullptr;
+ gPowerHalV1_0 = nullptr;
return -1;
}
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index edd7d53..4fb2ae3 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1523,6 +1523,10 @@
<< " satellites:: " << std::endl;
}
+ internalState << "constellation: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL; "
+ << "ephemerisType: 0=Eph, 1=Alm, 2=?; "
+ << "ephemerisSource: 0=Demod, 1=Supl, 2=Server, 3=?; "
+ << "ephemerisHealth: 0=Good, 1=Bad, 2=?" << std::endl;
for (size_t i = 0; i < data.satelliteDataArray.size(); i++) {
internalState << "svid: " << data.satelliteDataArray[i].svid
<< ", constellation: "
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 86c5e99..23e3f67 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -18,7 +18,7 @@
//#define LOG_NDEBUG 0
-#include <android/hardware/power/1.0/IPower.h>
+#include <android/hardware/power/1.1/IPower.h>
#include "JNIHelp.h"
#include "jni.h"
@@ -40,7 +40,7 @@
using android::hardware::Return;
using android::hardware::Void;
-using android::hardware::power::V1_0::IPower;
+using android::hardware::power::V1_1::IPower;
using android::hardware::power::V1_0::PowerHint;
using android::hardware::power::V1_0::Feature;
using android::String8;
@@ -56,7 +56,8 @@
// ----------------------------------------------------------------------------
static jobject gPowerManagerServiceObj;
-sp<IPower> gPowerHal = nullptr;
+sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
+sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
bool gPowerHalExists = true;
std::mutex gPowerHalMutex;
static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
@@ -79,16 +80,17 @@
// Check validity of current handle to the power HAL service, and call getService() if necessary.
// The caller must be holding gPowerHalMutex.
bool getPowerHal() {
- if (gPowerHalExists && gPowerHal == nullptr) {
- gPowerHal = IPower::getService();
- if (gPowerHal != nullptr) {
+ if (gPowerHalExists && gPowerHalV1_0 == nullptr) {
+ gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
+ if (gPowerHalV1_0 != nullptr) {
+ gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
ALOGI("Loaded power HAL service");
} else {
ALOGI("Couldn't load power HAL service");
gPowerHalExists = false;
}
}
- return gPowerHal != nullptr;
+ return gPowerHalV1_0 != nullptr;
}
// Check if a call to a power HAL function failed; if so, log the failure and invalidate the
@@ -96,7 +98,7 @@
static void processReturn(const Return<void> &ret, const char* functionName) {
if (!ret.isOk()) {
ALOGE("%s() failed: power HAL service not available.", functionName);
- gPowerHal = nullptr;
+ gPowerHalV1_0 = nullptr;
}
}
@@ -104,7 +106,12 @@
// Tell the power HAL when user activity occurs.
gPowerHalMutex.lock();
if (getPowerHal()) {
- Return<void> ret = gPowerHal->powerHint(PowerHint::INTERACTION, 0);
+ Return<void> ret;
+ if (gPowerHalV1_1 != nullptr) {
+ ret = gPowerHalV1_1->powerHintAsync(PowerHint::INTERACTION, 0);
+ } else {
+ ret = gPowerHalV1_0->powerHint(PowerHint::INTERACTION, 0);
+ }
processReturn(ret, "powerHint");
}
gPowerHalMutex.unlock();
@@ -161,7 +168,7 @@
"Excessive delay in setInteractive(%s) while turning screen %s",
enable ? "true" : "false", enable ? "on" : "off");
ALOGD_IF_SLOW(20, err);
- Return<void> ret = gPowerHal->setInteractive(enable);
+ Return<void> ret = gPowerHalV1_0->setInteractive(enable);
processReturn(ret, "setInteractive");
}
}
@@ -179,7 +186,12 @@
static void nativeSendPowerHint(JNIEnv *env, jclass clazz, jint hintId, jint data) {
std::lock_guard<std::mutex> lock(gPowerHalMutex);
if (getPowerHal()) {
- Return<void> ret = gPowerHal->powerHint((PowerHint)hintId, data);
+ Return<void> ret;
+ if (gPowerHalV1_1 != nullptr) {
+ ret = gPowerHalV1_1->powerHintAsync((PowerHint)hintId, data);
+ } else {
+ ret = gPowerHalV1_0->powerHint((PowerHint)hintId, data);
+ }
processReturn(ret, "powerHint");
}
}
@@ -187,7 +199,7 @@
static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint data) {
std::lock_guard<std::mutex> lock(gPowerHalMutex);
if (getPowerHal()) {
- Return<void> ret = gPowerHal->setFeature((Feature)featureId, static_cast<bool>(data));
+ Return<void> ret = gPowerHalV1_0->setFeature((Feature)featureId, static_cast<bool>(data));
processReturn(ret, "setFeature");
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index eca285a..c9be3a2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -775,13 +775,6 @@
mContentResolver = context.getContentResolver();
- if (!disableCameraService) {
- Slog.i(TAG, "Camera Service Proxy");
- traceBeginAndSlog("StartCameraServiceProxy");
- mSystemServiceManager.startService(CameraServiceProxy.class);
- traceEnd();
- }
-
// The AccountManager must come before the ContentService
traceBeginAndSlog("StartAccountManagerService");
mSystemServiceManager.startService(ACCOUNT_SERVICE_CLASS);
@@ -1531,6 +1524,12 @@
}
}
+ if (!disableCameraService) {
+ traceBeginAndSlog("StartCameraServiceProxy");
+ mSystemServiceManager.startService(CameraServiceProxy.class);
+ traceEnd();
+ }
+
// Before things start rolling, be sure we have decided whether
// we are in safe mode.
final boolean safeMode = wm.detectSafeMode();
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 0230ff2..4bd0bd2 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -1065,7 +1065,7 @@
mNwService.setIPv6AddrGenMode(mInterfaceName, mConfiguration.mIPv6AddrGenMode);
} catch (ServiceSpecificException e) {
if (e.errorCode != OsConstants.EOPNOTSUPP) {
- throw e;
+ logError("Unable to set IPv6 addrgen mode: %s", e);
}
}
}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java b/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java
index 3007cb1..f457f6a 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java
@@ -25,8 +25,14 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.internal.util.FastXmlSerializer;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -50,4 +56,15 @@
channel.setBlockableSystem(true);
assertEquals(true, channel.isBlockableSystem());
}
+
+ @Test
+ public void testEmptyVibration_noException() throws Exception {
+ NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
+ channel.setVibrationPattern(new long[0]);
+
+ XmlSerializer serializer = new FastXmlSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+ channel.writeXml(serializer);
+ }
}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 2e96f6f..8b3fb18 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -314,9 +314,9 @@
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
waitForIdle();
- StatusBarNotification[] notifs =
- mBinderService.getActiveNotifications(PKG);
+ StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
assertEquals(1, notifs.length);
+ assertEquals(1, mNotificationManagerService.getNotificationRecordCount());
}
@Test
@@ -328,6 +328,7 @@
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(PKG);
assertEquals(0, notifs.length);
+ assertEquals(0, mNotificationManagerService.getNotificationRecordCount());
}
@Test
@@ -342,6 +343,7 @@
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(PKG);
assertEquals(0, notifs.length);
+ assertEquals(0, mNotificationManagerService.getNotificationRecordCount());
}
@Test
@@ -354,6 +356,7 @@
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(sbn.getPackageName());
assertEquals(0, notifs.length);
+ assertEquals(0, mNotificationManagerService.getNotificationRecordCount());
}
@Test
@@ -366,6 +369,43 @@
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(sbn.getPackageName());
assertEquals(0, notifs.length);
+ assertEquals(0, mNotificationManagerService.getNotificationRecordCount());
+ }
+
+ @Test
+ public void testUserInitiatedClearAll_noLeak() throws Exception {
+ final NotificationRecord n = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ n.sbn.getId(), n.sbn.getNotification(), n.sbn.getUserId());
+ waitForIdle();
+
+ mNotificationManagerService.mNotificationDelegate.onClearAll(uid, Binder.getCallingPid(),
+ n.getUserId());
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(n.sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ assertEquals(0, mNotificationManagerService.getNotificationRecordCount());
+ }
+
+ @Test
+ public void testCancelAllNotificationsCancelsChildren() throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group1", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group1", false);
+
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
+ waitForIdle();
+
+ mBinderService.cancelAllNotifications(PKG, parent.sbn.getUserId());
+ waitForIdle();
+ assertEquals(0, mNotificationManagerService.getNotificationRecordCount());
}
@Test
@@ -377,6 +417,8 @@
}
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
waitForIdle();
+
+ assertEquals(0, mNotificationManagerService.getNotificationRecordCount());
}
@Test
@@ -403,6 +445,8 @@
parentAsChild.sbn.getId(), parentAsChild.sbn.getNotification(),
parentAsChild.sbn.getUserId());
waitForIdle();
+
+ assertEquals(0, mNotificationManagerService.getNotificationRecordCount());
}
@Test
@@ -416,6 +460,7 @@
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(sbn.getPackageName());
assertEquals(1, notifs.length);
+ assertEquals(1, mNotificationManagerService.getNotificationRecordCount());
}
@Test
@@ -429,6 +474,7 @@
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(sbn.getPackageName());
assertEquals(1, notifs.length);
+ assertEquals(1, mNotificationManagerService.getNotificationRecordCount());
}
@Test
@@ -441,6 +487,7 @@
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(sbn.getPackageName());
assertEquals(0, notifs.length);
+ assertEquals(0, mNotificationManagerService.getNotificationRecordCount());
}
@Test
@@ -454,6 +501,7 @@
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(sbn.getPackageName());
assertEquals(1, notifs.length);
+ assertEquals(1, mNotificationManagerService.getNotificationRecordCount());
}
@Test
@@ -483,6 +531,7 @@
mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId());
waitForIdle();
assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
+ assertEquals(0, mNotificationManagerService.getNotificationRecordCount());
}
@Test
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index 7c074da..303a577 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -118,27 +118,28 @@
/**
* @hide
*/
- public boolean parseDescriptors(byte[] descriptors) {
- try {
- mDescriptors.clear();
+ public void parseDescriptors(byte[] descriptors) {
+ mDescriptors.clear();
- ByteStream stream = new ByteStream(descriptors);
- while (stream.available() > 0) {
- UsbDescriptor descriptor = allocDescriptor(stream);
- if (descriptor != null) {
- // Parse
+ ByteStream stream = new ByteStream(descriptors);
+ while (stream.available() > 0) {
+ UsbDescriptor descriptor = allocDescriptor(stream);
+ if (descriptor != null) {
+ // Parse
+ try {
descriptor.parseRawDescriptors(stream);
- mDescriptors.add(descriptor);
-
- // Clean up
- descriptor.postParse(stream);
+ } catch (Exception ex) {
+ Log.e(TAG, "Exception parsing USB descriptors.", ex);
}
+
+ // Its OK to add the invalid descriptor as the postParse()
+ // routine will mark it as invalid.
+ mDescriptors.add(descriptor);
+
+ // Clean up
+ descriptor.postParse(stream);
}
- return true;
- } catch (Exception ex) {
- Log.e(TAG, "Exception parsing USB descriptors.", ex);
}
- return false;
}
/**
@@ -146,7 +147,11 @@
*/
public boolean parseDevice(String deviceAddr) {
byte[] rawDescriptors = getRawDescriptors(deviceAddr);
- return rawDescriptors != null && parseDescriptors(rawDescriptors);
+ if (rawDescriptors != null) {
+ parseDescriptors(rawDescriptors);
+ return true;
+ }
+ return false;
}
private native byte[] getRawDescriptors(String deviceAddr);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 9b3786e..f6deb0a 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1471,6 +1471,17 @@
public static final String IMSI_KEY_EXPIRATION_DAYS_TIME_INT =
"imsi_key_expiration_days_time_int";
+ /**
+ * Key identifying if the CDMA Caller ID presentation and suppression MMI codes
+ * should be converted to 3GPP CLIR codes when a multimode (CDMA+UMTS+LTE) device is roaming
+ * on a 3GPP network. Specifically *67<number> will be converted to #31#<number> and
+ * *82<number> will be converted to *31#<number> before dialing a call when this key is
+ * set TRUE and device is roaming on a 3GPP network.
+ * @hide
+ */
+ public static final String KEY_CONVERT_CDMA_CALLER_ID_MMI_CODES_WHILE_ROAMING_ON_3GPP_BOOL =
+ "convert_cdma_caller_id_mmi_codes_while_roaming_on_3gpp_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -1721,6 +1732,8 @@
sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
sDefaults.putInt(IMSI_KEY_EXPIRATION_DAYS_TIME_INT, IMSI_ENCRYPTION_DAYS_TIME_DISABLED);
sDefaults.putString(IMSI_KEY_DOWNLOAD_URL_STRING, null);
+ sDefaults.putBoolean(KEY_CONVERT_CDMA_CALLER_ID_MMI_CODES_WHILE_ROAMING_ON_3GPP_BOOL,
+ false);
}
/**
diff --git a/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java b/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java
index 7182147..0060901 100644
--- a/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java
+++ b/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java
@@ -62,21 +62,6 @@
}
@Test
- public void getColors_usesFallbackIfFails() {
- ExtractionType alwaysFail =
- (inWallpaperColors, outGradientColorsNormal, outGradientColorsDark,
- outGradientColorsExtraDark) -> false;
- ColorExtractor extractor = new ColorExtractor(mContext, alwaysFail);
- GradientColors colors = extractor.getColors(WallpaperManager.FLAG_SYSTEM);
-
- assertEquals("Should be using the fallback color.",
- colors.getMainColor(), ColorExtractor.FALLBACK_COLOR);
- assertEquals("Should be using the fallback color.",
- colors.getSecondaryColor(), ColorExtractor.FALLBACK_COLOR);
- assertFalse("Dark text support should be false.", colors.supportsDarkText());
- }
-
- @Test
public void getColors_usesExtractedColors() {
GradientColors colorsExpectedNormal = new GradientColors();
colorsExpectedNormal.setMainColor(Color.RED);
@@ -96,8 +81,6 @@
outGradientColorsNormal.set(colorsExpectedNormal);
outGradientColorsDark.set(colorsExpectedDark);
outGradientColorsExtraDark.set(colorsExpectedExtraDark);
- // Successful extraction
- return true;
};
ColorExtractor extractor = new ColorExtractor(mContext, type);
diff --git a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
index 1e3e8e9..6dc9ba7 100644
--- a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
+++ b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
@@ -20,6 +20,7 @@
import android.app.WallpaperColors;
import android.graphics.Color;
+import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.Range;
@@ -40,6 +41,32 @@
public class TonalTest {
@Test
+ public void extractInto_usesFallback() {
+ GradientColors normal = new GradientColors();
+ Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
+ tonal.extractInto(null, normal, new GradientColors(),
+ new GradientColors());
+ assertFalse("Should use fallback color if WallpaperColors is null.",
+ normal.getMainColor() == Tonal.MAIN_COLOR_LIGHT);
+ }
+
+ @Test
+ public void extractInto_usesFallbackWhenTooLightOrDark() {
+ GradientColors normal = new GradientColors();
+ Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
+ tonal.extractInto(new WallpaperColors(Color.valueOf(0xff000000), null, null, 0),
+ normal, new GradientColors(), new GradientColors());
+ assertTrue("Should use fallback color if WallpaperColors is too dark.",
+ normal.getMainColor() == Tonal.MAIN_COLOR_DARK);
+
+ tonal.extractInto(new WallpaperColors(Color.valueOf(0xffffffff), null, null,
+ WallpaperColors.HINT_SUPPORTS_DARK_TEXT),
+ normal, new GradientColors(), new GradientColors());
+ assertTrue("Should use fallback color if WallpaperColors is too light.",
+ normal.getMainColor() == Tonal.MAIN_COLOR_LIGHT);
+ }
+
+ @Test
public void colorRange_containsColor() {
Tonal.ColorRange colorRange = new Tonal.ColorRange(new Range<>(0f, 50f),
new Range<>(0f, 1f), new Range<>(0f, 1f));
@@ -64,16 +91,28 @@
}
@Test
- public void colorRange_excludeBlacklistedColor() {
- // Creating a WallpaperColors object that contains *only* blacklisted colors
- float[] hsl = Tonal.BLACKLISTED_COLORS[0].getCenter();
+ public void configParser_dataSanity() {
+ Tonal.ConfigParser config = new Tonal.ConfigParser(InstrumentationRegistry.getContext());
+ // 1 to avoid regression where only first item would be parsed.
+ assertTrue("Tonal palettes are empty", config.getTonalPalettes().size() > 1);
+ assertTrue("Blacklisted colors are empty", config.getBlacklistedColors().size() > 1);
+ }
+
+ @Test
+ public void tonal_excludeBlacklistedColor() {
+ // Make sure that palette generation will fail.
+ Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
+
+ // Creating a WallpaperColors object that contains *only* blacklisted colors.
+ float[] hsl = tonal.getBlacklistedColors().get(0).getCenter();
WallpaperColors colors = new WallpaperColors(Color.valueOf(ColorUtils.HSLToColor(hsl)),
null, null, 0);
// Make sure that palette generation will fail
- Tonal tonal = new Tonal();
- boolean success = tonal.extractInto(colors, new GradientColors(), new GradientColors(),
+ GradientColors normal = new GradientColors();
+ tonal.extractInto(colors, normal, new GradientColors(),
new GradientColors());
- assertFalse("Cannot generate a tonal palette from blacklisted colors ", success);
+ assertTrue("Cannot generate a tonal palette from blacklisted colors.",
+ normal.getMainColor() == Tonal.MAIN_COLOR_DARK);
}
}
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index acf9e8f7..a115146 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -178,6 +178,7 @@
mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
mLooper.getLooper(), mSystemProperties,
mTetheringDependencies);
+ verify(mNMService).registerTetheringStatsProvider(any(), anyString());
}
@After
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index 0e4a36c..dcb9723 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -16,26 +16,38 @@
package com.android.server.connectivity.tethering;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.TrafficStats.UID_TETHERING;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
+import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.net.ITetheringStatsProvider;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkStats;
import android.net.RouteInfo;
import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.INetworkManagementService;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -66,11 +78,14 @@
@Mock private OffloadHardwareInterface mHardware;
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
+ @Mock private INetworkManagementService mNMService;
private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
ArgumentCaptor.forClass(ArrayList.class);
+ private final ArgumentCaptor<ITetheringStatsProvider.Stub> mTetherStatsProviderCaptor =
+ ArgumentCaptor.forClass(ITetheringStatsProvider.Stub.class);
private MockContentResolver mContentResolver;
- @Before public void setUp() throws Exception {
+ @Before public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
when(mContext.getPackageName()).thenReturn("OffloadControllerTest");
@@ -88,14 +103,23 @@
when(mHardware.initOffloadConfig()).thenReturn(true);
when(mHardware.initOffloadControl(any(OffloadHardwareInterface.ControlCallback.class)))
.thenReturn(true);
+ when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats());
}
private void enableOffload() {
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
}
+ private OffloadController makeOffloadController() throws Exception {
+ OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()),
+ mHardware, mContentResolver, mNMService, new SharedLog("test"));
+ verify(mNMService).registerTetheringStatsProvider(
+ mTetherStatsProviderCaptor.capture(), anyString());
+ return offload;
+ }
+
@Test
- public void testNoSettingsValueDefaultDisabledDoesNotStart() {
+ public void testNoSettingsValueDefaultDisabledDoesNotStart() throws Exception {
setupFunctioningHardwareInterface();
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1);
try {
@@ -103,8 +127,7 @@
fail();
} catch (SettingNotFoundException expected) {}
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -116,7 +139,7 @@
}
@Test
- public void testNoSettingsValueDefaultEnabledDoesStart() {
+ public void testNoSettingsValueDefaultEnabledDoesStart() throws Exception {
setupFunctioningHardwareInterface();
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0);
try {
@@ -124,8 +147,7 @@
fail();
} catch (SettingNotFoundException expected) {}
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -137,12 +159,11 @@
}
@Test
- public void testSettingsAllowsStart() {
+ public void testSettingsAllowsStart() throws Exception {
setupFunctioningHardwareInterface();
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -154,12 +175,11 @@
}
@Test
- public void testSettingsDisablesStart() {
+ public void testSettingsDisablesStart() throws Exception {
setupFunctioningHardwareInterface();
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 1);
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -174,8 +194,7 @@
setupFunctioningHardwareInterface();
enableOffload();
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -240,6 +259,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(null), eq(null));
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
inOrder.verifyNoMoreInteractions();
final String ipv4Gateway = "192.0.2.1";
@@ -249,6 +269,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null));
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
inOrder.verifyNoMoreInteractions();
final String ipv6Gw1 = "fe80::cafe";
@@ -258,6 +279,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
ArrayList<String> v6gws = mStringArrayCaptor.getValue();
assertEquals(1, v6gws.size());
assertTrue(v6gws.contains(ipv6Gw1));
@@ -270,6 +292,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
v6gws = mStringArrayCaptor.getValue();
assertEquals(2, v6gws.size());
assertTrue(v6gws.contains(ipv6Gw1));
@@ -287,6 +310,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
v6gws = mStringArrayCaptor.getValue();
assertEquals(2, v6gws.size());
assertTrue(v6gws.contains(ipv6Gw1));
@@ -321,6 +345,7 @@
assertEquals(2, v6gws.size());
assertTrue(v6gws.contains(ipv6Gw1));
assertTrue(v6gws.contains(ipv6Gw2));
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
inOrder.verifyNoMoreInteractions();
// Completely identical LinkProperties updates are de-duped.
@@ -331,4 +356,65 @@
anyObject(), anyObject(), anyObject(), anyObject());
inOrder.verifyNoMoreInteractions();
}
+
+ private void assertNetworkStats(String iface, ForwardedStats stats, NetworkStats.Entry entry) {
+ assertEquals(iface, entry.iface);
+ assertEquals(stats.rxBytes, entry.rxBytes);
+ assertEquals(stats.txBytes, entry.txBytes);
+ assertEquals(SET_DEFAULT, entry.set);
+ assertEquals(TAG_NONE, entry.tag);
+ assertEquals(UID_TETHERING, entry.uid);
+ }
+
+ @Test
+ public void testGetForwardedStats() throws Exception {
+ setupFunctioningHardwareInterface();
+ enableOffload();
+
+ final OffloadController offload = makeOffloadController();
+ offload.start();
+
+ final String ethernetIface = "eth1";
+ final String mobileIface = "rmnet_data0";
+
+ ForwardedStats ethernetStats = new ForwardedStats();
+ ethernetStats.rxBytes = 12345;
+ ethernetStats.txBytes = 54321;
+
+ ForwardedStats mobileStats = new ForwardedStats();
+ mobileStats.rxBytes = 999;
+ mobileStats.txBytes = 99999;
+
+ when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats);
+ when(mHardware.getForwardedStats(eq(mobileIface))).thenReturn(mobileStats);
+
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(ethernetIface);
+ offload.setUpstreamLinkProperties(lp);
+
+ lp.setInterfaceName(mobileIface);
+ offload.setUpstreamLinkProperties(lp);
+
+ lp.setInterfaceName(ethernetIface);
+ offload.setUpstreamLinkProperties(lp);
+
+ ethernetStats.rxBytes = 100000;
+ ethernetStats.txBytes = 100000;
+ offload.setUpstreamLinkProperties(null);
+
+ NetworkStats stats = mTetherStatsProviderCaptor.getValue().getTetherStats();
+ assertEquals(2, stats.size());
+
+ NetworkStats.Entry entry = null;
+ int ethernetPosition = ethernetIface.equals(stats.getValues(0, entry).iface) ? 0 : 1;
+ int mobilePosition = 1 - ethernetPosition;
+
+ entry = stats.getValues(mobilePosition, entry);
+ assertNetworkStats(mobileIface, mobileStats, entry);
+
+ ethernetStats.rxBytes = 12345 + 100000;
+ ethernetStats.txBytes = 54321 + 100000;
+ entry = stats.getValues(ethernetPosition, entry);
+ assertNetworkStats(ethernetIface, ethernetStats, entry);
+ }
}