Merge changes from topic 'camera-tron' into oc-dr1-dev
* changes:
CameraServiceProxy: Log camera usage metrics
CameraServiceProxy: Add CameraStatsLoggingService, event dumping
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/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/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/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..1f8de04 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -808,7 +808,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 +832,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/provider/Settings.java b/core/java/android/provider/Settings.java
index 41cc12b..e84a041 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6515,6 +6515,12 @@
public static final String DOZE_PULSE_ON_PICK_UP = "doze_pulse_on_pick_up";
/**
+ * Whether the device should pulse on long press gesture.
+ * @hide
+ */
+ public static final String DOZE_PULSE_ON_LONG_PRESS = "doze_pulse_on_long_press";
+
+ /**
* Whether the device should pulse on double tap gesture.
* @hide
*/
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 7538f65..ba9e05c 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -150,6 +150,11 @@
public final static int PRESENCE_INTERNAL = 1 << 0;
public final static int PRESENCE_EXTERNAL = 1 << 1;
+ // Navigation bar position values
+ int NAV_BAR_LEFT = 1 << 0;
+ int NAV_BAR_RIGHT = 1 << 1;
+ int NAV_BAR_BOTTOM = 1 << 2;
+
public final static boolean WATCH_POINTER = false;
/**
@@ -1676,6 +1681,14 @@
public boolean isNavBarForcedShownLw(WindowState win);
/**
+ * @return The side of the screen where navigation bar is positioned.
+ * @see #NAV_BAR_LEFT
+ * @see #NAV_BAR_RIGHT
+ * @see #NAV_BAR_BOTTOM
+ */
+ int getNavBarPosition();
+
+ /**
* Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
* bar or button bar. See {@link #getNonDecorDisplayWidth}.
*
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..04819a5 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;
@@ -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..e78ca38 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -44,24 +44,54 @@
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;
+
// Temporary variable to avoid allocations
private float[] mTmpHSL = new float[3];
/**
- * 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 +150,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 +164,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,18 +203,17 @@
// 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);
@@ -181,6 +226,33 @@
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];
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index 445a82c..df9c27b 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -36,6 +36,7 @@
return pulseOnNotificationEnabled(user)
|| pulseOnPickupEnabled(user)
|| pulseOnDoubleTapEnabled(user)
+ || pulseOnLongPressEnabled(user)
|| alwaysOnEnabled(user);
}
@@ -79,6 +80,19 @@
return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
}
+ public String longPressSensorType() {
+ return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);
+ }
+
+ public boolean pulseOnLongPressEnabled(int user) {
+ return pulseOnLongPressAvailable() && boolSettingDefaultOff(
+ Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, user);
+ }
+
+ private boolean pulseOnLongPressAvailable() {
+ return !TextUtils.isEmpty(longPressSensorType());
+ }
+
public boolean alwaysOnEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_ALWAYS_ON, user)
&& alwaysOnAvailable();
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/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 425fd95..797335f 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1521,7 +1521,7 @@
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Koristi prečicu"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izaberite funkciju koja će se koristiti kada dodirnete dugme Pristupačnost:"</string>
+ <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Odaberite funkciju koja će se koristiti kada dodirnete dugme Pristupačnost:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Da promijenite funkcije, dodirnite i držite dugme Pristupačnost."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Uvećanje"</string>
<string name="user_switched" msgid="3768006783166984410">"Trenutni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
@@ -1748,7 +1748,7 @@
<string name="user_creation_adding" msgid="4482658054622099197">"Da li dozvoljavate da <xliff:g id="APP">%1$s</xliff:g> kreira novog korisnika za <xliff:g id="ACCOUNT">%2$s</xliff:g> (Korisnik sa ovim nalogom već postoji)?"</string>
<string name="language_selection_title" msgid="2680677278159281088">"Dodaj jezik"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Izbor regije"</string>
- <string name="search_language_hint" msgid="7042102592055108574">"Ukucajte ime jezika"</string>
+ <string name="search_language_hint" msgid="7042102592055108574">"Upišite ime jezika"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
<string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
<string name="region_picker_section_all" msgid="8966316787153001779">"Sve regije"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index faaa6a2..db531b5 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1308,7 +1308,7 @@
<string name="submit" msgid="1602335572089911941">"Enviar"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Se ha habilitado el modo coche"</string>
<string name="car_mode_disable_notification_message" msgid="6301524980144350051">"Toca para salir del modo coche."</string>
- <string name="tethered_notification_title" msgid="3146694234398202601">"Compartir Internet/Zona Wi-Fi activado"</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Compartir conexión/Zona Wi-Fi activada"</string>
<string name="tethered_notification_message" msgid="2113628520792055377">"Toca para configurar."</string>
<string name="back_button_label" msgid="2300470004503343439">"Atrás"</string>
<string name="next_button_label" msgid="1080555104677992408">"Siguiente"</string>
@@ -1395,7 +1395,7 @@
<string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Límite de datos móviles superado"</string>
<string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Límite de datos Wi-Fi superado"</string>
<string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Límite superado en <xliff:g id="SIZE">%s</xliff:g>"</string>
- <string name="data_usage_restricted_title" msgid="5965157361036321914">"Conexiones automáticas restringidas"</string>
+ <string name="data_usage_restricted_title" msgid="5965157361036321914">"Datos en segundo plano restringidos"</string>
<string name="data_usage_restricted_body" msgid="469866376337242726">"Toca para quitar la restricción."</string>
<string name="ssl_certificate" msgid="6510040486049237639">"Certificado de seguridad"</string>
<string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Este certificado es válido."</string>
@@ -1630,7 +1630,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instalado por el administrador"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizado por el administrador"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado por el administrador"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Para mejorar la duración de la batería, la función de ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de la transmisión de datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de batería se desactiva automáticamente cuando el dispositivo se está cargando."</string>
+ <string name="battery_saver_description" msgid="1960431123816253034">"Para mejorar la duración de la batería, la función de ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de los datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de batería se desactiva automáticamente cuando el dispositivo se está cargando."</string>
<string name="data_saver_description" msgid="6015391409098303235">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se muestren hasta que no las toques."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 951933c..686bdf1 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1782,8 +1782,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Ebakuatu kostaldeak eta ibaialdeak berehala eta joan toki seguru batera, adibidez, toki garai batera."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Ez larritu eta bilatu babesleku bat inguruan."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Larrialdi-mezuen proba"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Erantzun"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Ez da onartzen SIM txartela"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Ez dago SIM txartelik"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index cbd23b2..e26ca99 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1781,8 +1781,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Évacuez immédiatement les zones côtières et les rives des fleuves, et réfugiez-vous dans un endroit plus sécuritaire, comme un terrain surélevé."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Restez calme et cherchez un abri à proximité."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test de messages d\'urgence"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Répondre"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Carte SIM non autorisée"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Carte SIM non configurée"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index f9a7673..660eb02 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1432,7 +1432,7 @@
<string name="media_route_button_content_description" msgid="591703006349356016">"Caster"</string>
<string name="media_route_chooser_title" msgid="1751618554539087622">"Connexion à l\'appareil"</string>
<string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Caster l\'écran sur l\'appareil"</string>
- <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils en cours…"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils…"</string>
<string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Paramètres"</string>
<string name="media_route_controller_disconnect" msgid="8966120286374158649">"Déconnecter"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Analyse en cours..."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f413565..a36903a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -849,7 +849,7 @@
<string name="save_password_remember" msgid="6491879678996749466">"याद रखें"</string>
<string name="save_password_never" msgid="8274330296785855105">"कभी नहीं"</string>
<string name="open_permission_deny" msgid="7374036708316629800">"आपके पास इस पेज को खोलने की अनुमति नहीं है."</string>
- <string name="text_copied" msgid="4985729524670131385">"लेख की क्लिपबोर्ड पर प्रतिलिपि बनाई गई."</string>
+ <string name="text_copied" msgid="4985729524670131385">"लेख को क्लिपबोर्ड पर कॉपी किया गया."</string>
<string name="more_item_label" msgid="4650918923083320495">"अधिक"</string>
<string name="prepend_shortcut_label" msgid="2572214461676015642">"मेनू+"</string>
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"space"</string>
@@ -966,12 +966,12 @@
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"सभी को चुनें"</string>
<string name="cut" msgid="3092569408438626261">"काटें"</string>
- <string name="copy" msgid="2681946229533511987">"प्रतिलिपि बनाएं"</string>
+ <string name="copy" msgid="2681946229533511987">"कॉपी करें"</string>
<string name="paste" msgid="5629880836805036433">"चिपकाएं"</string>
<string name="paste_as_plain_text" msgid="5427792741908010675">"सादे पाठ के रूप में चिपकाएं"</string>
<string name="replace" msgid="5781686059063148930">"बदलें•"</string>
<string name="delete" msgid="6098684844021697789">"हटाएं"</string>
- <string name="copyUrl" msgid="2538211579596067402">"URL की प्रतिलिपि बनाएं"</string>
+ <string name="copyUrl" msgid="2538211579596067402">"URL को कॉपी करें"</string>
<string name="selectTextMode" msgid="1018691815143165326">"लेख को चुनें"</string>
<string name="undo" msgid="7905788502491742328">"वापस लाएं"</string>
<string name="redo" msgid="7759464876566803888">"फिर से करें"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 5e68ade..7f35c28 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -579,8 +579,8 @@
<string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Կարգավորել, որ սարքի համընդհանուր պրոքսի-սերվերն օգտագործվի, երբ քաղաքականությունը միացված է: Միայն սարքի սեփականատերը կարող է կարգավորել համընդհանուր պրոքսի-սերվերը:"</string>
<string name="policylab_expirePassword" msgid="5610055012328825874">"Նշել էկր կողպ գաղտնաբ սպառումը"</string>
<string name="policydesc_expirePassword" msgid="5367525762204416046">"Փոխել էկրանի կողպման գաղտնաբառի, PIN-ի կամ նախշի փոփոխման հաճախականությունը:"</string>
- <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Կարգավորել պահոցի կոդավորումը"</string>
- <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Պահանջել, որ պահվող հավելվածների տվյալները լինեն կոդավորված:"</string>
+ <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Կարգավորել պահոցի գաղտնագրումը"</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Պահանջել, որ պահվող հավելվածների տվյալները լինեն գաղտնագրված:"</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"Կասեցնել տեսախցիկները"</string>
<string name="policydesc_disableCamera" msgid="2306349042834754597">"Կանխել բոլոր սարքերի ֆոտոխցիկների օգտագործումը:"</string>
<string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Անջատել կողպման գործառույթները"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 8e813ab..445ff94 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1849,8 +1849,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"יש להתפנות מיידית מאזורים הסמוכים לחופים ולנהרות למקום בטוח יותר, כגון שטח גבוה יותר."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"הישאר רגוע וחפש מחסה בקרבת מקום."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"בדיקה של הודעות חירום"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"השב"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"כרטיס ה-SIM לא מורשה"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"כרטיס ה-SIM לא מזוהה"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 9356169..34ca6b1 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1781,8 +1781,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"ອົບພະຍົບອອກຈາກເຂດຊາຍຝັ່ງທະເລ ແລະ ບໍລິເວນແມ່ນ້ຳໄປບ່ອນທີ່ປອດໄພກວ່າ ເຊັ່ນ: ບ່ອນສູງ ໂດຍທັນທີ."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"ໃຈເຢັນໆ ແລະ ຊອກຫາບ່ອນພັກຢູ່ໃກ້ໆ."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"ທົດສອບຂໍ້ຄວາມສຸກເສີນ"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ຕອບກັບ"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ SIM"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"ບໍ່ມີການນຳໃຊ້ SIM"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 0a5804f..45ae315 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1849,8 +1849,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Takoj se umaknite z obalnih območij in bregov rek na varnejše mesto, na primer na višje ležeča mesta."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Ostanite mirni in poiščite zavetje v bližini."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Preskus sporočil v sili"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odgovor"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Kartica SIM ni dovoljena"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Kartica SIM ni omogočena za uporabo"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ab0353e..9ef46a7 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1781,8 +1781,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Kıyı kesimlerini ve nehir kenarlarını hemen boşaltarak yüksek yerler gibi daha güvenli bölgelere gidin."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Sakin olun ve yakınlarda sığınabileceğiniz bir yer bulun."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Acil durum mesajları testi"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Yanıtla"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM\'e izin verilmiyor"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM için temel hazırlık yapılmadı"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 0560330..c2ee71f 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1011,7 +1011,7 @@
<string name="whichSendApplicationNamed" msgid="2799370240005424391">"使用%1$s分享"</string>
<string name="whichSendApplicationLabel" msgid="4579076294675975354">"分享"</string>
<string name="whichSendToApplication" msgid="8272422260066642057">"通过以下应用发送"</string>
- <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"通过1$s发送"</string>
+ <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"通过%1$s发送"</string>
<string name="whichSendToApplicationLabel" msgid="8878962419005813500">"发送"</string>
<string name="whichHomeApplication" msgid="4307587691506919691">"选择主屏幕应用"</string>
<string name="whichHomeApplicationNamed" msgid="4493438593214760979">"将“%1$s”设为主屏幕应用"</string>
@@ -1781,8 +1781,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"请立即从沿海和河滨区域撤离到高地等较安全的地方。"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"请保持冷静,并寻找附近的避难地点。"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"紧急消息测试"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"回复"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"不受允许的 SIM 卡"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"未配置的 SIM 卡"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4520f75..7b437fa 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1849,6 +1849,9 @@
<!-- Type of the double tap sensor. Empty if double tap is not supported. -->
<string name="config_dozeDoubleTapSensorType" translatable="false"></string>
+ <!-- Type of the long press sensor. Empty if long press is not supported. -->
+ <string name="config_dozeLongPressSensorType" translatable="false"></string>
+
<!-- Control whether the always on display mode is available. This should only be enabled on
devices where the display has be tuned to be power efficient in DOZE and/or DOZE_SUSPEND
states. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2135027..2d7a5d3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3044,6 +3044,8 @@
<java-symbol type="array" name="config_hideWhenDisabled_packageNames" />
+ <java-symbol type="string" name="config_dozeLongPressSensorType" />
+
<java-symbol type="array" name="config_allowedGlobalInstantAppSettings" />
<java-symbol type="array" name="config_allowedSystemInstantAppSettings" />
<java-symbol type="array" name="config_allowedSecureInstantAppSettings" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 01dfd32..ca53885 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -430,6 +430,7 @@
Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS,
Settings.Secure.DISPLAY_DENSITY_FORCED,
Settings.Secure.DOZE_ALWAYS_ON,
+ Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT,
Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index f5f1024..833376c 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -21,6 +21,8 @@
import android.util.Base64;
import android.util.TimeUtils;
+import java.util.Arrays;
+
import com.android.internal.location.nano.GnssLogsProto.GnssLog;
/**
@@ -40,6 +42,7 @@
locationFailureStatistics = new Statistics();
timeToFirstFixSecStatistics = new Statistics();
positionAccuracyMeterStatistics = new Statistics();
+ topFourAverageCn0Statistics = new Statistics();
reset();
}
@@ -95,6 +98,27 @@
return;
}
+ /*
+ * Logs CN0 when at least 4 SVs are available
+ *
+ */
+ public void logCn0(float[] cn0s, int numSv) {
+ if (numSv < 4) {
+ return;
+ }
+ float[] cn0Array = Arrays.copyOf(cn0s, numSv);
+ Arrays.sort(cn0Array);
+ if (cn0Array[numSv - 4] > 0.0) {
+ double top4AvgCn0 = 0.0;
+ for (int i = numSv - 4; i < numSv; i++) {
+ top4AvgCn0 += (double) cn0Array[i];
+ }
+ top4AvgCn0 /= 4;
+ topFourAverageCn0Statistics.addItem(top4AvgCn0);
+ }
+ return;
+ }
+
/**
* Dumps GNSS metrics as a proto string
* @return
@@ -117,6 +141,12 @@
msg.standardDeviationPositionAccuracyMeters
= (int) positionAccuracyMeterStatistics.getStandardDeviation();
}
+ if (topFourAverageCn0Statistics.getCount() > 0) {
+ msg.numTopFourAverageCn0Processed = topFourAverageCn0Statistics.getCount();
+ msg.meanTopFourAverageCn0DbHz = topFourAverageCn0Statistics.getMean();
+ msg.standardDeviationTopFourAverageCn0DbHz
+ = topFourAverageCn0Statistics.getStandardDeviation();
+ }
String s = Base64.encodeToString(GnssLog.toByteArray(msg), Base64.DEFAULT);
reset();
return s;
@@ -155,6 +185,14 @@
s.append(" Position accuracy standard deviation (m): ").append(
positionAccuracyMeterStatistics.getStandardDeviation()).append("\n");
}
+ s.append(" Number of CN0 reports: ").append(
+ topFourAverageCn0Statistics.getCount()).append("\n");
+ if (topFourAverageCn0Statistics.getCount() > 0) {
+ s.append(" Top 4 Avg CN0 mean (dB-Hz): ").append(
+ topFourAverageCn0Statistics.getMean()).append("\n");
+ s.append(" Top 4 Avg CN0 standard deviation (dB-Hz): ").append(
+ topFourAverageCn0Statistics.getStandardDeviation()).append("\n");
+ }
s.append("GNSS_KPI_END").append("\n");
return s.toString();
}
@@ -211,6 +249,9 @@
/** Position accuracy statistics */
private Statistics positionAccuracyMeterStatistics;
+ /** Top 4 average CN0 statistics */
+ private Statistics topFourAverageCn0Statistics;
+
/**
* Resets GNSS metrics
*/
@@ -221,6 +262,7 @@
locationFailureStatistics.reset();
timeToFirstFixSecStatistics.reset();
positionAccuracyMeterStatistics.reset();
+ topFourAverageCn0Statistics.reset();
return;
}
}
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/preference_two_target.xml b/packages/SettingsLib/res/layout/preference_two_target.xml
index 7000940..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/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-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 8af0ab5..9a6595e 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -97,7 +97,7 @@
<string name="phone_label" msgid="2320074140205331708">"otvori telefon"</string>
<string name="voice_assist_label" msgid="3956854378310019854">"otvori glasovnu pomoć"</string>
<string name="camera_label" msgid="7261107956054836961">"otvori kameru"</string>
- <string name="recents_caption_resize" msgid="3517056471774958200">"Izaberite novi raspored zadataka"</string>
+ <string name="recents_caption_resize" msgid="3517056471774958200">"Odaberite novi raspored zadataka"</string>
<string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Dugme za uvećavanje u slučaju nekompatibilnosti."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Uvećani prikaz manjeg ekrana na većem ekranu."</string>
@@ -355,8 +355,8 @@
<string name="description_target_search" msgid="3091587249776033139">"Pretraživanje"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Povucite gore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Povucite lijevo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <string name="zen_priority_introduction" msgid="7577965386868311310">"Neće vas ometati zvukovi i vibracije, osim alarma, podsjetnika, događaja i pozivalaca koje odredite. I dalje ćete čuti sve što ste izabrali za reprodukciju, uključujući muziku, videozapise i igre."</string>
- <string name="zen_alarms_introduction" msgid="7034415210361973827">"Neće vas ometati zvukovi i vibracije, osim alarma. I dalje ćete čuti sve što ste izabrali za reprodukciju, uključujući muziku, videozapise i igre."</string>
+ <string name="zen_priority_introduction" msgid="7577965386868311310">"Neće vas ometati zvukovi i vibracije, osim alarma, podsjetnika, događaja i pozivalaca koje odredite. I dalje ćete čuti sve što ste odabrali za reprodukciju, uključujući muziku, videozapise i igre."</string>
+ <string name="zen_alarms_introduction" msgid="7034415210361973827">"Neće vas ometati zvukovi i vibracije, osim alarma. I dalje ćete čuti sve što ste odabrali za reprodukciju, uključujući muziku, videozapise i igre."</string>
<string name="zen_priority_customize_button" msgid="7948043278226955063">"Prilagodi"</string>
<string name="zen_silence_introduction_voice" msgid="2284540992298200729">"Ovim se blokiraju SVI zvukovi i vibracije, uključujući alarme, muziku, videozapise i igre. I dalje ćete moći obavljati pozive."</string>
<string name="zen_silence_introduction" msgid="3137882381093271568">"Ovim se blokiraju SVI zvukovi i vibracije, uključujući alarme, muziku, video zapise i igre."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 7911cab..869bca7 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -314,7 +314,7 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Weitere Einstellungen"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Fertig"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Verbunden"</string>
- <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Verbunden, Akkustand <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Verbunden, Akkustand: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"Verbindung wird hergestellt…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 78457bd..bb44d99 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -310,7 +310,7 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Περισσότερες ρυθμίσεις"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Τέλος"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Συνδέθηκε"</string>
- <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Σύνδεση, μπαταρία <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Συνδεδεμένη, μπαταρία <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"Σύνδεση…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Πρόσδεση"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Σημείο πρόσβασης Wi-Fi"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 434b048..f8bd8ff 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -155,7 +155,7 @@
<string name="accessibility_cell_data" msgid="5326139158682385073">"Datos móviles"</string>
<string name="accessibility_cell_data_on" msgid="5927098403452994422">"Datos móviles activados"</string>
<string name="accessibility_cell_data_off" msgid="443267573897409704">"Datos móviles desactivados"</string>
- <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Compartir por Bluetooth"</string>
+ <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Compartir conexión por Bluetooth"</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"Modo avión"</string>
<string name="accessibility_vpn_on" msgid="5993385083262856059">"La red VPN está activada."</string>
<string name="accessibility_no_sims" msgid="3957997018324995781">"No hay tarjeta SIM."</string>
@@ -314,7 +314,7 @@
<string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
<string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Conectado (<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería)"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
- <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Compartir Internet"</string>
+ <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Compartir conexión"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificaciones"</string>
<string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Linterna"</string>
@@ -407,7 +407,7 @@
<string name="user_remove_user_message" msgid="1453218013959498039">"Se eliminarán todas las aplicaciones y todos los datos de este usuario."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Quitar"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
- <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y el envío de datos en segundo plano"</string>
+ <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y los datos en segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar ahorro de batería"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> empezará a capturar todo lo que aparezca en la pantalla."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string>
@@ -589,7 +589,7 @@
<string name="battery_panel_title" msgid="7944156115535366613">"Uso de la batería"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ahorro de batería no disponible mientras se carga el dispositivo"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Ahorro de batería"</string>
- <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce el rendimiento y las conexiones automáticas"</string>
+ <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce el rendimiento y los datos en segundo plano"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Inicio"</string>
<string name="keyboard_key_back" msgid="2337450286042721351">"Atrás"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 1e817dd..0d5e58f 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -312,8 +312,7 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Ezarpen gehiago"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Eginda"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Konektatuta"</string>
- <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
- <skip />
+ <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Konektatuta. Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"Konektatzen…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Konexioa partekatzea"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Sare publikoa"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 3fe787d..6166671 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -310,7 +310,7 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Setelan lainnya"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Selesai"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Tersambung"</string>
- <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Terhubung, daya baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Terhubung, baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"Menyambung..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Menambatkan"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 2d4dd17..f424a30 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -534,7 +534,7 @@
<string name="tuner_warning" msgid="8730648121973575701">"System UI Tuner מספק לך דרכים נוספות להתאים אישית את ממשק המשתמש של Android. התכונות הניסיוניות האלה עשויות להשתנות, להתקלקל או להיעלם בגרסאות עתידיות. המשך בזהירות."</string>
<string name="tuner_persistent_warning" msgid="8597333795565621795">"התכונות הניסיוניות האלה עשויות להשתנות, להתקלקל או להיעלם בגרסאות עתידיות. המשך בזהירות."</string>
<string name="got_it" msgid="2239653834387972602">"הבנתי"</string>
- <string name="tuner_toast" msgid="603429811084428439">"מזל טוב! System UI Tuner נוסף ל\'הגדרות\'"</string>
+ <string name="tuner_toast" msgid="603429811084428439">"מזל טוב! ה-System UI Tuner נוסף ל\'הגדרות\'"</string>
<string name="remove_from_settings" msgid="8389591916603406378">"הסר מההגדרות"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"האם להסיר את System UI Tuner ולהפסיק להשתמש בכל התכונות שלו?"</string>
<string name="activity_not_found" msgid="348423244327799974">"האפליקציה אינה מותקנת במכשיר"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index cb9c77b..906b40f 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -310,8 +310,7 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"更多设置"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"完成"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"已连接"</string>
- <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
- <skip />
+ <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"已连接,电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"正在连接…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"网络共享"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"热点"</string>
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/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index ccb8117..3c895ab 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;
@@ -47,10 +48,10 @@
@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/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index ce0a151..0993ace 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -35,7 +35,7 @@
private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
- private static final int PULSE_REASONS = 5;
+ private static final int PULSE_REASONS = 6;
public static final int PULSE_REASON_NONE = -1;
public static final int PULSE_REASON_INTENT = 0;
@@ -43,6 +43,7 @@
public static final int PULSE_REASON_SENSOR_SIGMOTION = 2;
public static final int PULSE_REASON_SENSOR_PICKUP = 3;
public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
+ public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5;
private static boolean sRegisterKeyguardCallback = true;
@@ -179,6 +180,7 @@
case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion";
case PULSE_REASON_SENSOR_PICKUP: return "pickup";
case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
+ case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress";
default: throw new IllegalArgumentException("bad reason: " + pulseReason);
}
}
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/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 545a1ea..0d5527c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -98,7 +98,14 @@
Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP,
true /* configured */,
DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP,
- dozeParameters.doubleTapReportsTouchCoordinates())
+ dozeParameters.doubleTapReportsTouchCoordinates()),
+ new TriggerSensor(
+ findSensorWithType(config.longPressSensorType()),
+ Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
+ false /* settingDef */,
+ true /* configured */,
+ DozeLog.PULSE_REASON_SENSOR_LONG_PRESS,
+ true /* reports touch coordinates */),
};
mProxSensor = new ProxSensor();
@@ -263,6 +270,7 @@
final int mPulseReason;
final String mSetting;
final boolean mReportsTouchCoordinates;
+ final boolean mSettingDefault;
private boolean mRequested;
private boolean mRegistered;
@@ -270,8 +278,15 @@
public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason,
boolean reportsTouchCoordinates) {
+ this(sensor, setting, true /* settingDef */, configured, pulseReason,
+ reportsTouchCoordinates);
+ }
+
+ public TriggerSensor(Sensor sensor, String setting, boolean settingDef,
+ boolean configured, int pulseReason, boolean reportsTouchCoordinates) {
mSensor = sensor;
mSetting = setting;
+ mSettingDefault = settingDef;
mConfigured = configured;
mPulseReason = pulseReason;
mReportsTouchCoordinates = reportsTouchCoordinates;
@@ -305,7 +320,7 @@
if (TextUtils.isEmpty(mSetting)) {
return true;
}
- return Settings.Secure.getIntForUser(mResolver, mSetting, 1,
+ return Settings.Secure.getIntForUser(mResolver, mSetting, mSettingDefault ? 1 : 0,
UserHandle.USER_CURRENT) != 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index ec6caf1..d1f5337 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -123,8 +123,9 @@
float screenX, float screenY) {
boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
+ boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS;
- if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
+ if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) && !isLongPress) {
proximityCheckThenCall((result) -> {
if (result == ProximityCheck.RESULT_NEAR) {
// In pocket, drop event.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
index a10aa54..b8535a3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
@@ -61,6 +61,7 @@
private boolean mSlashed;
private Mode mTintMode;
private ColorStateList mTintList;
+ private boolean mAnimationEnabled = true;
public SlashDrawable(Drawable d) {
mDrawable = d;
@@ -97,6 +98,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 +124,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
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 e5aad03..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/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ea6e88a..ec6f747 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4596,11 +4596,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() {
@@ -5336,6 +5338,12 @@
@Override
public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
+ if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) {
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
+ startAssist(new Bundle());
+ return;
+ }
+
mDozeScrimController.pulse(new PulseCallback() {
@Override
@@ -7234,6 +7242,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/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/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
index a81188a..690186e 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,12 @@
@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);
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 +74,6 @@
outGradientColorsNormal.set(colors);
outGradientColorsDark.set(colors);
outGradientColorsExtraDark.set(colors);
- return true;
}, false);
simulateEvent(extractor);
extractor.setWallpaperVisible(true);
@@ -91,7 +88,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/proto/src/gnss.proto b/proto/src/gnss.proto
index 33a5584..c54ddad 100644
--- a/proto/src/gnss.proto
+++ b/proto/src/gnss.proto
@@ -33,4 +33,13 @@
// Standard deviation of position accuracy (in meters)
optional int32 standard_deviation_position_accuracy_meters = 8;
+
+ // Number of top 4 average CN0 processed
+ optional int32 num_top_four_average_cn0_processed = 9;
+
+ // Mean of top 4 average CN0 (dB-Hz)
+ optional double mean_top_four_average_cn0_db_hz = 10;
+
+ // Standard deviation of top 4 average CN0 (dB-Hz)
+ optional double standard_deviation_top_four_average_cn0_db_hz = 11;
}
\ No newline at end of file
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/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 6a8f6d3..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;
@@ -74,6 +75,7 @@
import static android.os.Build.VERSION_CODES.O;
import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
@@ -154,6 +156,7 @@
import android.view.IApplicationToken;
import android.view.WindowManager.LayoutParams;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.ReferrerIntent;
import com.android.internal.util.XmlUtils;
@@ -2319,10 +2322,12 @@
outBounds.setEmpty();
final float maxAspectRatio = info.maxAspectRatio;
final ActivityStack stack = getStack();
- if (task == null || stack == null || !task.mFullscreen || maxAspectRatio == 0) {
+ if (task == null || stack == null || !task.mFullscreen || maxAspectRatio == 0
+ || isInVrUiMode(getConfiguration())) {
// We don't set override configuration if that activity task isn't fullscreen. I.e. the
// activity is in multi-window mode. Or, there isn't a max aspect ratio specified for
- // the activity. This is indicated by an empty {@link outBounds}.
+ // the activity. This is indicated by an empty {@link outBounds}. We also don't set it
+ // if we are in VR mode.
return;
}
@@ -2358,6 +2363,17 @@
// Compute configuration based on max supported width and height.
outBounds.set(0, 0, maxActivityWidth, maxActivityHeight);
+ // Position the activity frame on the opposite side of the nav bar.
+ final int navBarPosition = service.mWindowManager.getNavBarPosition();
+ final int left = navBarPosition == NAV_BAR_LEFT
+ ? configuration.appBounds.right - outBounds.width() : 0;
+ outBounds.offsetTo(left, 0 /* top */);
+ }
+
+ /** Get bounds of the activity. */
+ @VisibleForTesting
+ Rect getBounds() {
+ return new Rect(mBounds);
}
/**
@@ -2581,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/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 518e12d..777a368 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -745,6 +745,13 @@
return null;
}
+ final TaskRecord bottomTask() {
+ if (mTaskHistory.isEmpty()) {
+ return null;
+ }
+ return mTaskHistory.get(0);
+ }
+
TaskRecord taskForIdLocked(int id) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
@@ -1902,7 +1909,14 @@
// the recents activity from an app.
behindFullscreenActivity = true;
}
-
+ } else if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Skipping after task=" + task
+ + " returning to non-application type=" + task.getTaskToReturnTo());
+ // Once we reach a fullscreen task that should return to another task, then no
+ // other activities behind that one should be visible.
+ if (task.getTaskToReturnTo() != APPLICATION_ACTIVITY_TYPE) {
+ behindFullscreenActivity = true;
+ }
}
}
@@ -2887,10 +2901,13 @@
transit = TRANSIT_TASK_OPEN_BEHIND;
} else {
// If a new task is being launched, then mark the existing top activity as
- // supporting picture-in-picture while pausing
+ // supporting picture-in-picture while pausing only if the starting activity
+ // would not be considered an overlay on top of the current activity
+ // (eg. not fullscreen, or the assistant)
if (focusedTopActivity != null
&& focusedTopActivity.getStackId() != PINNED_STACK_ID
- && r.getStackId() != ASSISTANT_STACK_ID) {
+ && r.getStackId() != ASSISTANT_STACK_ID
+ && r.fullscreen) {
focusedTopActivity.supportsPictureInPictureWhilePausing = true;
}
transit = TRANSIT_TASK_OPEN;
@@ -3372,6 +3389,16 @@
* @param allowFocusSelf Is the focus allowed to remain on the same stack.
*/
private boolean adjustFocusToNextFocusableStackLocked(String reason, boolean allowFocusSelf) {
+ if (isAssistantStack() && bottomTask() != null &&
+ bottomTask().getTaskToReturnTo() == HOME_ACTIVITY_TYPE) {
+ // If the current stack is the assistant stack, then use the return-to type to determine
+ // whether to return to the home screen. This is needed to workaround an issue where
+ // launching a fullscreen task (and subequently returning from that task) will cause
+ // the fullscreen stack to be found as the next focusable stack below, even if the
+ // assistant was launched over home.
+ return mStackSupervisor.moveHomeStackTaskToTop(reason);
+ }
+
final ActivityStack stack = mStackSupervisor.getNextFocusableStackLocked(
allowFocusSelf ? null : this);
final String myReason = reason + " adjustFocusToNextFocusableStack";
@@ -4555,9 +4582,10 @@
updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
}
// If a new task is moved to the front, then mark the existing top activity as supporting
- // picture-in-picture while paused
+ // picture-in-picture while paused only if the task would not be considered an oerlay on top
+ // of the current activity (eg. not fullscreen, or the assistant)
if (topActivity != null && topActivity.getStackId() != PINNED_STACK_ID
- && tr.getStackId() != ASSISTANT_STACK_ID) {
+ && tr.getStackId() != ASSISTANT_STACK_ID && tr.containsOnlyFullscreenActivities()) {
topActivity.supportsPictureInPictureWhilePausing = true;
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4f211e3..96d8573 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1112,6 +1112,19 @@
return intent != null ? intent : affinityIntent;
}
+ /**
+ * @return Whether there are only fullscreen activities in this task.
+ */
+ boolean containsOnlyFullscreenActivities() {
+ for (int i = 0; i < mActivities.size(); i++) {
+ final ActivityRecord r = mActivities.get(i);
+ if (!r.finishing && !r.fullscreen) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/** Returns the first non-finishing activity from the root. */
ActivityRecord getRootActivity() {
for (int i = 0; i < mActivities.size(); i++) {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 0a9dba7..b0be8f7 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -57,6 +57,7 @@
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
import android.net.wifi.WifiManager;
import android.os.Binder;
@@ -213,13 +214,13 @@
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 );
+ mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
mForwardedDownstreams = new HashSet<>();
mSimChange = new SimChangeListener(
- mContext, mTetherMasterSM.getHandler(), () -> reevaluateSimCardProvisioning());
+ mContext, smHandler, () -> reevaluateSimCardProvisioning());
mStateReceiver = new StateReceiver();
IntentFilter filter = new IntentFilter();
@@ -227,13 +228,13 @@
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler());
+ mContext.registerReceiver(mStateReceiver, filter, null, smHandler);
filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_SHARED);
filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
filter.addDataScheme("file");
- mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler());
+ mContext.registerReceiver(mStateReceiver, filter, null, smHandler);
// load device config info
updateConfiguration();
@@ -1142,12 +1143,6 @@
}
}
- private void startOffloadController() {
- mOffloadController.start();
- mOffloadController.updateExemptPrefixes(
- mUpstreamNetworkMonitor.getOffloadExemptPrefixes());
- }
-
class TetherMasterSM extends StateMachine {
private static final int BASE_MASTER = Protocol.BASE_TETHERING;
// an interface SM has requested Tethering/Local Hotspot
@@ -1165,14 +1160,14 @@
static final int CMD_CLEAR_ERROR = BASE_MASTER + 6;
static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7;
- private State mInitialState;
- private State mTetherModeAliveState;
+ private final State mInitialState;
+ private final State mTetherModeAliveState;
- private State mSetIpForwardingEnabledErrorState;
- private State mSetIpForwardingDisabledErrorState;
- private State mStartTetheringErrorState;
- private State mStopTetheringErrorState;
- private State mSetDnsForwardersErrorState;
+ private final State mSetIpForwardingEnabledErrorState;
+ private final State mSetIpForwardingDisabledErrorState;
+ private final State mStartTetheringErrorState;
+ private final State mStopTetheringErrorState;
+ private final State mSetDnsForwardersErrorState;
// This list is a little subtle. It contains all the interfaces that currently are
// requesting tethering, regardless of whether these interfaces are still members of
@@ -1212,22 +1207,46 @@
mNotifyList = new ArrayList<>();
mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog);
+
setInitialState(mInitialState);
}
+ private void startOffloadController() {
+ mOffloadController.start();
+ sendOffloadExemptPrefixes();
+ }
+
+ private void sendOffloadExemptPrefixes() {
+ sendOffloadExemptPrefixes(mUpstreamNetworkMonitor.getLocalPrefixes());
+ }
+
+ private void sendOffloadExemptPrefixes(Set<IpPrefix> localPrefixes) {
+ // Add in well-known minimum set.
+ PrefixUtils.addNonForwardablePrefixes(localPrefixes);
+ // Add tragically hardcoded prefixes.
+ localPrefixes.add(PrefixUtils.DEFAULT_WIFI_P2P_PREFIX);
+
+ // Add prefixes for all downstreams, regardless of IP serving mode.
+ for (TetherInterfaceStateMachine tism : mNotifyList) {
+ localPrefixes.addAll(PrefixUtils.localPrefixesFrom(tism.linkProperties()));
+ }
+
+ mOffloadController.setLocalPrefixes(localPrefixes);
+ }
+
class InitialState extends State {
@Override
public boolean processMessage(Message message) {
logMessage(this, message.what);
switch (message.what) {
case EVENT_IFACE_SERVING_STATE_ACTIVE:
- TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
+ TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
handleInterfaceServingStateActive(message.arg1, who);
transitionTo(mTetherModeAliveState);
break;
case EVENT_IFACE_SERVING_STATE_INACTIVE:
- who = (TetherInterfaceStateMachine)message.obj;
+ who = (TetherInterfaceStateMachine) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
handleInterfaceServingStateInactive(who);
break;
@@ -1422,8 +1441,8 @@
}
private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
- if (arg1 == UpstreamNetworkMonitor.NOTIFY_EXEMPT_PREFIXES) {
- mOffloadController.updateExemptPrefixes((Set<IpPrefix>) o);
+ if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) {
+ sendOffloadExemptPrefixes((Set<IpPrefix>) o);
return;
}
@@ -1527,7 +1546,7 @@
boolean retValue = true;
switch (message.what) {
case EVENT_IFACE_SERVING_STATE_ACTIVE: {
- TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
+ TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
handleInterfaceServingStateActive(message.arg1, who);
who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
@@ -1541,7 +1560,7 @@
break;
}
case EVENT_IFACE_SERVING_STATE_INACTIVE: {
- TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
+ TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
handleInterfaceServingStateInactive(who);
@@ -1573,6 +1592,9 @@
mOffloadController.notifyDownstreamLinkProperties(newLp);
} else {
mOffloadController.removeDownstreamInterface(newLp.getInterfaceName());
+ // Another interface might be in local-only hotspot mode;
+ // resend all local prefixes to the OffloadController.
+ sendOffloadExemptPrefixes();
}
break;
}
@@ -1614,7 +1636,7 @@
boolean retValue = true;
switch (message.what) {
case EVENT_IFACE_SERVING_STATE_ACTIVE:
- TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
+ TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
who.sendMessage(mErrorNotification);
break;
case CMD_CLEAR_ERROR:
@@ -1737,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 2b0ded9..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,20 +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
@@ -40,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;
@@ -47,14 +67,33 @@
private boolean mConfigInitialized;
private boolean mControlInitialized;
private LinkProperties mUpstreamLinkProperties;
+ // The complete set of offload-exempt prefixes passed in via Tethering from
+ // all upstream and downstream sources.
private Set<IpPrefix> mExemptPrefixes;
+ // A strictly "smaller" set of prefixes, wherein offload-approved prefixes
+ // (e.g. downstream on-link prefixes) have been removed and replaced with
+ // 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() {
@@ -126,6 +165,7 @@
public void stop() {
final boolean wasStarted = started();
+ updateStatsForCurrentUpstream();
mUpstreamLinkProperties = null;
mHwInterface.stopOffloadControl();
mControlInitialized = false;
@@ -133,26 +173,83 @@
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()) return;
+ 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 updateExemptPrefixes(Set<IpPrefix> exemptPrefixes) {
+ public void setLocalPrefixes(Set<IpPrefix> localPrefixes) {
if (!started()) return;
- mExemptPrefixes = exemptPrefixes;
- // TODO:
- // - add IP addresses from all downstream link properties
- // - add routes from all non-tethering downstream link properties
- // - remove any 64share prefixes
- // - push this to the HAL
+ mExemptPrefixes = localPrefixes;
+ computeAndPushLocalPrefixes();
}
public void notifyDownstreamLinkProperties(LinkProperties lp) {
@@ -215,4 +312,54 @@
return mHwInterface.setUpstreamParameters(
iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways));
}
+
+ private boolean computeAndPushLocalPrefixes() {
+ final Set<String> localPrefixStrs = computeLocalPrefixStrings(
+ mExemptPrefixes, mUpstreamLinkProperties);
+ if (mLastLocalPrefixStrs.equals(localPrefixStrs)) return true;
+
+ mLastLocalPrefixStrs = localPrefixStrs;
+ return mHwInterface.setLocalPrefixes(new ArrayList<>(localPrefixStrs));
+ }
+
+ // TODO: Factor in downstream LinkProperties once that information is available.
+ private static Set<String> computeLocalPrefixStrings(
+ Set<IpPrefix> localPrefixes, LinkProperties upstreamLinkProperties) {
+ // Create an editable copy.
+ final Set<IpPrefix> prefixSet = new HashSet<>(localPrefixes);
+
+ // TODO: If a downstream interface (not currently passed in) is reusing
+ // the /64 of the upstream (64share) then:
+ //
+ // [a] remove that /64 from the local prefixes
+ // [b] add in /128s for IP addresses on the downstream interface
+ // [c] add in /128s for IP addresses on the upstream interface
+ //
+ // Until downstream information is available here, simply add /128s from
+ // the upstream network; they'll just be redundant with their /64.
+ if (upstreamLinkProperties != null) {
+ for (LinkAddress linkAddr : upstreamLinkProperties.getLinkAddresses()) {
+ if (!linkAddr.isGlobalPreferred()) continue;
+ final InetAddress ip = linkAddr.getAddress();
+ if (!(ip instanceof Inet6Address)) continue;
+ prefixSet.add(new IpPrefix(ip, 128));
+ }
+ }
+
+ final HashSet<String> localPrefixStrs = new HashSet<>();
+ 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/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index b648f51..4df566f 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -168,6 +168,26 @@
return stats;
}
+ public boolean setLocalPrefixes(ArrayList<String> localPrefixes) {
+ final String logmsg = String.format("setLocalPrefixes([%s])",
+ String.join(",", localPrefixes));
+
+ final CbResults results = new CbResults();
+ try {
+ mOffloadControl.setLocalPrefixes(localPrefixes,
+ (boolean success, String errMsg) -> {
+ results.success = success;
+ results.errMsg = errMsg;
+ });
+ } catch (RemoteException e) {
+ record(logmsg, e);
+ return false;
+ }
+
+ record(logmsg, results);
+ return results.success;
+ }
+
public boolean setUpstreamParameters(
String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
iface = (iface != null) ? iface : NO_INTERFACE_NAME;
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 4bac69c..69678df 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -161,6 +161,8 @@
public int lastError() { return mLastError; }
+ public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); }
+
public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); }
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index eb66767..c5f7528 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -34,6 +34,7 @@
import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.util.NetworkConstants;
+import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
import android.util.Log;
@@ -72,16 +73,11 @@
private static final boolean DBG = false;
private static final boolean VDBG = false;
- private static final IpPrefix[] MINIMUM_LOCAL_PREFIXES_SET = {
- prefix("127.0.0.0/8"), prefix("169.254.0.0/16"),
- prefix("::/3"), prefix("fe80::/64"), prefix("fc00::/7"), prefix("ff00::/8"),
- };
-
public static final int EVENT_ON_AVAILABLE = 1;
public static final int EVENT_ON_CAPABILITIES = 2;
public static final int EVENT_ON_LINKPROPERTIES = 3;
public static final int EVENT_ON_LOST = 4;
- public static final int NOTIFY_EXEMPT_PREFIXES = 10;
+ public static final int NOTIFY_LOCAL_PREFIXES = 10;
private static final int CALLBACK_LISTEN_ALL = 1;
private static final int CALLBACK_TRACK_DEFAULT = 2;
@@ -93,7 +89,7 @@
private final Handler mHandler;
private final int mWhat;
private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
- private HashSet<IpPrefix> mOffloadExemptPrefixes;
+ private HashSet<IpPrefix> mLocalPrefixes;
private ConnectivityManager mCM;
private NetworkCallback mListenAllCallback;
private NetworkCallback mDefaultNetworkCallback;
@@ -107,7 +103,7 @@
mHandler = mTarget.getHandler();
mLog = log.forSubComponent(TAG);
mWhat = what;
- mOffloadExemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values());
+ mLocalPrefixes = new HashSet<>();
}
@VisibleForTesting
@@ -223,8 +219,8 @@
return typeStatePair.ns;
}
- public Set<IpPrefix> getOffloadExemptPrefixes() {
- return (Set<IpPrefix>) mOffloadExemptPrefixes.clone();
+ public Set<IpPrefix> getLocalPrefixes() {
+ return (Set<IpPrefix>) mLocalPrefixes.clone();
}
private void handleAvailable(int callbackType, Network network) {
@@ -360,11 +356,11 @@
notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
}
- private void recomputeOffloadExemptPrefixes() {
- final HashSet<IpPrefix> exemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values());
- if (!mOffloadExemptPrefixes.equals(exemptPrefixes)) {
- mOffloadExemptPrefixes = exemptPrefixes;
- notifyTarget(NOTIFY_EXEMPT_PREFIXES, exemptPrefixes.clone());
+ private void recomputeLocalPrefixes() {
+ final HashSet<IpPrefix> localPrefixes = allLocalPrefixes(mNetworkMap.values());
+ if (!mLocalPrefixes.equals(localPrefixes)) {
+ mLocalPrefixes = localPrefixes;
+ notifyTarget(NOTIFY_LOCAL_PREFIXES, localPrefixes.clone());
}
}
@@ -402,7 +398,7 @@
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
handleLinkProp(network, newLp);
- recomputeOffloadExemptPrefixes();
+ recomputeLocalPrefixes();
}
// TODO: Handle onNetworkSuspended();
@@ -411,7 +407,7 @@
@Override
public void onLost(Network network) {
handleLost(mCallbackType, network);
- recomputeOffloadExemptPrefixes();
+ recomputeLocalPrefixes();
}
}
@@ -460,35 +456,15 @@
return result;
}
- private static HashSet<IpPrefix> allOffloadExemptPrefixes(Iterable<NetworkState> netStates) {
+ private static HashSet<IpPrefix> allLocalPrefixes(Iterable<NetworkState> netStates) {
final HashSet<IpPrefix> prefixSet = new HashSet<>();
- addDefaultLocalPrefixes(prefixSet);
-
for (NetworkState ns : netStates) {
- addOffloadExemptPrefixes(prefixSet, ns.linkProperties);
+ final LinkProperties lp = ns.linkProperties;
+ if (lp == null) continue;
+ prefixSet.addAll(PrefixUtils.localPrefixesFrom(lp));
}
return prefixSet;
}
-
- private static void addDefaultLocalPrefixes(Set<IpPrefix> prefixSet) {
- Collections.addAll(prefixSet, MINIMUM_LOCAL_PREFIXES_SET);
- }
-
- private static void addOffloadExemptPrefixes(Set<IpPrefix> prefixSet, LinkProperties lp) {
- if (lp == null) return;
-
- for (LinkAddress linkAddr : lp.getAllLinkAddresses()) {
- prefixSet.add(new IpPrefix(linkAddr.getAddress(), linkAddr.getPrefixLength()));
- }
-
- // TODO: Consider adding other non-default routes associated with this
- // network. Traffic to these destinations should perhaps not go through
- // the Internet (upstream).
- }
-
- private static IpPrefix prefix(String prefixStr) {
- return new IpPrefix(prefixStr);
- }
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 4511aa9..601dd94 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1651,6 +1651,9 @@
mSvAzimuths,
mSvCarrierFreqs);
+ // Log CN0 as part of GNSS metrics
+ mGnssMetrics.logCn0(mCn0s, svCount);
+
if (VERBOSE) {
Log.v(TAG, "SV count: " + svCount);
}
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/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8425d23..75fc25a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -358,10 +358,6 @@
private static final String SYSUI_SCREENSHOT_ERROR_RECEIVER =
"com.android.systemui.screenshot.ScreenshotServiceErrorReceiver";
- private static final int NAV_BAR_BOTTOM = 0;
- private static final int NAV_BAR_RIGHT = 1;
- private static final int NAV_BAR_LEFT = 2;
-
/**
* Keyguard stuff
*/
@@ -6943,6 +6939,12 @@
}
@Override
+ public int getNavBarPosition() {
+ // TODO(multi-display): Support system decor on secondary displays.
+ return mNavigationBarPosition;
+ }
+
+ @Override
public boolean isDockSideAllowed(int dockSide) {
// We do not allow all dock sides at which the navigation bar touches the docked stack.
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 839ee0e..b9d02a9 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1357,8 +1357,10 @@
* @return {@code true} If all children have been considered, {@code false}.
*/
private boolean allDrawnStatesConsidered() {
- for (WindowState child : mChildren) {
- if (!child.getDrawnStatedEvaluated()) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowState child = mChildren.get(i);
+ if (child.mightAffectAllDrawn(false /*visibleOnly*/ )
+ && !child.getDrawnStateEvaluated()) {
return false;
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9fe7381..05f4626 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1073,7 +1073,7 @@
}
if (w.mHasSurface && !rotateSeamlessly) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
- w.mOrientationChanging = true;
+ w.setOrientationChanging(true);
mService.mRoot.mOrientationChangeComplete = false;
w.mLastFreezeDuration = 0;
}
@@ -2679,10 +2679,10 @@
mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
forAllWindows(w -> {
- if (!w.mOrientationChanging) {
+ if (!w.getOrientationChanging()) {
return;
}
- w.mOrientationChanging = false;
+ w.setOrientationChanging(false);
w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
- mService.mDisplayFreezeTime);
Slog.w(TAG_WM, "Force clearing orientation change: " + w);
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index 01a3143..5dc79f8 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -17,13 +17,14 @@
package com.android.server.wm;
import android.util.Slog;
-import android.view.Display;
import java.util.ArrayDeque;
import java.util.function.Consumer;
+import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -56,7 +57,6 @@
mService = service;
}
- private int mHighestApplicationLayer = 0;
private ArrayDeque<WindowState> mPinnedWindows = new ArrayDeque<>();
private ArrayDeque<WindowState> mDockedWindows = new ArrayDeque<>();
private ArrayDeque<WindowState> mAssistantWindows = new ArrayDeque<>();
@@ -66,6 +66,8 @@
private int mCurBaseLayer;
private int mCurLayer;
private boolean mAnyLayerChanged;
+ private int mHighestApplicationLayer;
+ private int mHighestDockedAffectedLayer;
private int mHighestLayerInImeTargetBaseLayer;
private WindowState mImeTarget;
private boolean mAboveImeTarget;
@@ -98,6 +100,10 @@
mHighestLayerInImeTargetBaseLayer = Math.max(mHighestLayerInImeTargetBaseLayer,
w.mWinAnimator.mAnimLayer);
}
+ if (w.getAppToken() != null && StackId.isResizeableByDockedStack(w.getStackId())) {
+ mHighestDockedAffectedLayer = Math.max(mHighestDockedAffectedLayer,
+ w.mWinAnimator.mAnimLayer);
+ }
collectSpecialWindows(w);
@@ -135,7 +141,6 @@
}
private void reset() {
- mHighestApplicationLayer = 0;
mPinnedWindows.clear();
mInputMethodWindows.clear();
mDockedWindows.clear();
@@ -147,8 +152,10 @@
mCurLayer = 0;
mAnyLayerChanged = false;
- mImeTarget = mService.mInputMethodTarget;
+ mHighestApplicationLayer = 0;
+ mHighestDockedAffectedLayer = 0;
mHighestLayerInImeTargetBaseLayer = (mImeTarget != null) ? mImeTarget.mBaseLayer : 0;
+ mImeTarget = mService.mInputMethodTarget;
mAboveImeTarget = false;
mAboveImeTargetAppWindows.clear();
}
@@ -179,32 +186,41 @@
}
}
- final Task task = w.getTask();
- if (task == null) {
- return;
- }
- final TaskStack stack = task.mStack;
- if (stack == null) {
- return;
- }
- if (stack.mStackId == PINNED_STACK_ID) {
+ final int stackId = w.getAppToken() != null ? w.getStackId() : INVALID_STACK_ID;
+ if (stackId == PINNED_STACK_ID) {
mPinnedWindows.add(w);
- } else if (stack.mStackId == DOCKED_STACK_ID) {
+ } else if (stackId == DOCKED_STACK_ID) {
mDockedWindows.add(w);
- } else if (stack.mStackId == ASSISTANT_STACK_ID) {
+ } else if (stackId == ASSISTANT_STACK_ID) {
mAssistantWindows.add(w);
}
}
private void adjustSpecialWindows() {
- int layer = mHighestApplicationLayer + WINDOW_LAYER_MULTIPLIER;
- // For pinned and docked stack window, we want to make them above other windows also when
- // these windows are animating.
- while (!mDockedWindows.isEmpty()) {
- layer = assignAndIncreaseLayerIfNeeded(mDockedWindows.remove(), layer);
+ // The following adjustments are beyond the highest docked-affected layer
+ int layer = mHighestDockedAffectedLayer + WINDOW_LAYER_MULTIPLIER;
+
+ // Adjust the docked stack windows and dock divider above only the windows that are affected
+ // by the docked stack. When this happens, also boost the assistant window layers, otherwise
+ // the docked stack windows & divider would be promoted above the assistant.
+ if (!mDockedWindows.isEmpty() && mHighestDockedAffectedLayer > 0) {
+ while (!mDockedWindows.isEmpty()) {
+ final WindowState window = mDockedWindows.remove();
+ layer = assignAndIncreaseLayerIfNeeded(window, layer);
+ }
+
+ layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
+
+ while (!mAssistantWindows.isEmpty()) {
+ final WindowState window = mAssistantWindows.remove();
+ if (window.mLayer > mHighestDockedAffectedLayer) {
+ layer = assignAndIncreaseLayerIfNeeded(window, layer);
+ }
+ }
}
- layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
+ // The following adjustments are beyond the highest app layer or boosted layer
+ layer = Math.max(layer, mHighestApplicationLayer + WINDOW_LAYER_MULTIPLIER);
// We know that we will be animating a relaunching window in the near future, which will
// receive a z-order increase. We want the replaced window to immediately receive the same
@@ -213,12 +229,6 @@
layer = assignAndIncreaseLayerIfNeeded(mReplacingWindows.remove(), layer);
}
- // Adjust the assistant stack windows to be above the docked and fullscreen stack windows,
- // but under the pinned stack windows
- while (!mAssistantWindows.isEmpty()) {
- layer = assignAndIncreaseLayerIfNeeded(mAssistantWindows.remove(), layer);
- }
-
while (!mPinnedWindows.isEmpty()) {
layer = assignAndIncreaseLayerIfNeeded(mPinnedWindows.remove(), layer);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ebfeac3..17e87a0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5789,7 +5789,7 @@
// orientation.
if (!okToDisplay() && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Changing surface while display frozen: " + w);
- w.mOrientationChanging = true;
+ w.setOrientationChanging(true);
w.mLastFreezeDuration = 0;
mRoot.mOrientationChangeComplete = false;
if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
@@ -6292,6 +6292,22 @@
}
}
+ /**
+ * Used by ActivityManager to determine where to position an app with aspect ratio shorter then
+ * the screen is.
+ * @see WindowManagerPolicy#getNavBarPosition()
+ */
+ public int getNavBarPosition() {
+ synchronized (mWindowMap) {
+ // Perform layout if it was scheduled before to make sure that we get correct nav bar
+ // position when doing rotations.
+ final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
+ defaultDisplayContent.performLayout(false /* initial */,
+ false /* updateInputWindows */);
+ return mPolicy.getNavBarPosition();
+ }
+ }
+
@Override
public WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name,
InputEventReceiver.Factory inputEventReceiverFactory) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1e0acbc..34ff9e8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -441,7 +441,7 @@
* Set when the orientation is changing and this window has not yet
* been updated for the new orientation.
*/
- boolean mOrientationChanging;
+ private boolean mOrientationChanging;
/**
* The orientation during the last visible call to relayout. If our
@@ -685,7 +685,7 @@
/**
* Returns whether this {@link WindowState} has been considered for drawing by its parent.
*/
- boolean getDrawnStatedEvaluated() {
+ boolean getDrawnStateEvaluated() {
return mDrawnStateEvaluated;
}
@@ -1184,7 +1184,8 @@
// then we need to hold off on unfreezing the display until this window has been
// redrawn; to do that, we need to go through the process of getting informed by the
// application when it has finished drawing.
- if (mOrientationChanging || dragResizingChanged || isResizedWhileNotDragResizing()) {
+ if (getOrientationChanging() || dragResizingChanged
+ || isResizedWhileNotDragResizing()) {
if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) {
Slog.v(TAG_WM, "Orientation or resize start waiting for draw"
+ ", mDrawState=DRAW_PENDING in " + this
@@ -1199,17 +1200,33 @@
if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG_WM, "Resizing window " + this);
mService.mResizingWindows.add(this);
}
- } else if (mOrientationChanging) {
+ } else if (getOrientationChanging()) {
if (isDrawnLw()) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Orientation not waiting for draw in "
+ this + ", surfaceController " + winAnimator.mSurfaceController);
- mOrientationChanging = false;
+ setOrientationChanging(false);
mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
- mService.mDisplayFreezeTime);
}
}
}
+ boolean getOrientationChanging() {
+ // In addition to the local state flag, we must also consider the difference in the last
+ // reported configuration vs. the current state. If the client code has not been informed of
+ // the change, logic dependent on having finished processing the orientation, such as
+ // unfreezing, could be improperly triggered.
+ // TODO(b/62846907): Checking against {@link mLastReportedConfiguration} could be flaky as
+ // this is not necessarily what the client has processed yet. Find a
+ // better indicator consistent with the client.
+ return mOrientationChanging || (isVisible()
+ && getConfiguration().orientation != mLastReportedConfiguration.orientation);
+ }
+
+ void setOrientationChanging(boolean changing) {
+ mOrientationChanging = changing;
+ }
+
DisplayContent getDisplayContent() {
return mToken.getDisplayContent();
}
@@ -2669,10 +2686,10 @@
mAppFreezing = false;
- if (mHasSurface && !mOrientationChanging
+ if (mHasSurface && !getOrientationChanging()
&& mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "set mOrientationChanging of " + this);
- mOrientationChanging = true;
+ setOrientationChanging(true);
mService.mRoot.mOrientationChangeComplete = false;
}
mLastFreezeDuration = 0;
@@ -3091,7 +3108,7 @@
mWinAnimator.mSurfaceResized = false;
mReportOrientationChanged = false;
} catch (RemoteException e) {
- mOrientationChanging = false;
+ setOrientationChanging(false);
mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
- mService.mDisplayFreezeTime);
// We are assuming the hosting process is dead or in a zombie state.
@@ -3350,7 +3367,11 @@
pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
pw.print(prefix); pw.print(" isAnimatingWithSavedSurface()=");
pw.print(isAnimatingWithSavedSurface());
- pw.print(" mAppDied=");pw.println(mAppDied);
+ pw.print(" mAppDied=");pw.print(mAppDied);
+ pw.print(prefix); pw.print("drawnStateEvaluated=");
+ pw.print(getDrawnStateEvaluated());
+ pw.print(prefix); pw.print("mightAffectAllDrawn=");
+ pw.println(mightAffectAllDrawn(false /*visibleOnly*/));
}
pw.print(prefix); pw.print("mViewVisibility=0x");
pw.print(Integer.toHexString(mViewVisibility));
@@ -3450,10 +3471,13 @@
pw.print(" mDestroying="); pw.print(mDestroying);
pw.print(" mRemoved="); pw.println(mRemoved);
}
- if (mOrientationChanging || mAppFreezing || mTurnOnScreen
+ if (getOrientationChanging() || mAppFreezing || mTurnOnScreen
|| mReportOrientationChanged) {
pw.print(prefix); pw.print("mOrientationChanging=");
pw.print(mOrientationChanging);
+ pw.print(" configOrientationChanging=");
+ pw.print(mLastReportedConfiguration.orientation
+ != getConfiguration().orientation);
pw.print(" mAppFreezing="); pw.print(mAppFreezing);
pw.print(" mTurnOnScreen="); pw.print(mTurnOnScreen);
pw.print(" mReportOrientationChanged="); pw.println(mReportOrientationChanged);
@@ -3490,6 +3514,8 @@
if (computeDragResizing()) {
pw.print(prefix); pw.println("computeDragResizing=" + computeDragResizing());
}
+ pw.print(prefix); pw.println("isOnScreen=" + isOnScreen());
+ pw.print(prefix); pw.println("isVisible=" + isVisible());
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index cd55156..8f1065f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1527,11 +1527,11 @@
// There is no need to wait for an animation change if our window is gone for layout
// already as we'll never be visible.
- if (w.mOrientationChanging && w.isGoneForLayoutLw()) {
+ if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
if (DEBUG_ORIENTATION) {
Slog.v(TAG, "Orientation change skips hidden " + w);
}
- w.mOrientationChanging = false;
+ w.setOrientationChanging(false);
}
return;
}
@@ -1564,8 +1564,8 @@
// really hidden (gone for layout), there is no point in still waiting for it.
// Note that this does introduce a potential glitch if the window becomes unhidden
// before it has drawn for the new orientation.
- if (w.mOrientationChanging && w.isGoneForLayoutLw()) {
- w.mOrientationChanging = false;
+ if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
+ w.setOrientationChanging(false);
if (DEBUG_ORIENTATION) Slog.v(TAG,
"Orientation change skips hidden " + w);
}
@@ -1618,7 +1618,7 @@
mAnimator.setPendingLayoutChanges(w.getDisplayId(),
WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
} else {
- w.mOrientationChanging = false;
+ w.setOrientationChanging(false);
}
}
if (hasSurface()) {
@@ -1631,14 +1631,14 @@
displayed = true;
}
- if (w.mOrientationChanging) {
+ if (w.getOrientationChanging()) {
if (!w.isDrawnLw()) {
mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
mAnimator.mLastWindowFreezeSource = w;
if (DEBUG_ORIENTATION) Slog.v(TAG,
"Orientation continue waiting for draw in " + w);
} else {
- w.mOrientationChanging = false;
+ w.setOrientationChanging(false);
if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change complete in " + w);
}
}
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/net/java/android/net/util/PrefixUtils.java b/services/net/java/android/net/util/PrefixUtils.java
new file mode 100644
index 0000000..962aab4
--- /dev/null
+++ b/services/net/java/android/net/util/PrefixUtils.java
@@ -0,0 +1,74 @@
+/*
+ * 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.util;
+
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+
+/**
+ * @hide
+ */
+public class PrefixUtils {
+ private static final IpPrefix[] MIN_NON_FORWARDABLE_PREFIXES = {
+ pfx("127.0.0.0/8"), // IPv4 loopback
+ pfx("169.254.0.0/16"), // IPv4 link-local, RFC3927#section-8
+ pfx("::/3"),
+ pfx("fe80::/64"), // IPv6 link-local
+ pfx("fc00::/7"), // IPv6 ULA
+ pfx("ff02::/8"), // IPv6 link-local multicast
+ };
+
+ public static final IpPrefix DEFAULT_WIFI_P2P_PREFIX = pfx("192.168.49.0/24");
+
+ public static Set<IpPrefix> getNonForwardablePrefixes() {
+ final HashSet<IpPrefix> prefixes = new HashSet<>();
+ addNonForwardablePrefixes(prefixes);
+ return prefixes;
+ }
+
+ public static void addNonForwardablePrefixes(Set<IpPrefix> prefixes) {
+ Collections.addAll(prefixes, MIN_NON_FORWARDABLE_PREFIXES);
+ }
+
+ public static Set<IpPrefix> localPrefixesFrom(LinkProperties lp) {
+ final HashSet<IpPrefix> localPrefixes = new HashSet<>();
+ if (lp == null) return localPrefixes;
+
+ for (LinkAddress addr : lp.getAllLinkAddresses()) {
+ if (addr.getAddress().isLinkLocalAddress()) continue;
+ localPrefixes.add(asIpPrefix(addr));
+ }
+ // TODO: Add directly-connected routes as well (ones from which we did
+ // not also form a LinkAddress)?
+
+ return localPrefixes;
+ }
+
+ public static IpPrefix asIpPrefix(LinkAddress addr) {
+ return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
+ }
+
+ private static IpPrefix pfx(String prefixStr) {
+ return new IpPrefix(prefixStr);
+ }
+}
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/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index f75d49c..2252c85 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -16,10 +16,15 @@
package com.android.server.am;
+import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM;
+import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
+import static android.view.WindowManagerPolicy.NAV_BAR_RIGHT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.when;
import android.content.ComponentName;
+import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
@@ -94,4 +99,36 @@
return -1;
}
+
+ @Test
+ public void testPositionLimitedAspectRatioNavBarBottom() throws Exception {
+ verifyPositionWithLimitedAspectRatio(NAV_BAR_BOTTOM, new Rect(0, 0, 1000, 2000), 1.5f,
+ new Rect(0, 0, 1000, 1500));
+ }
+
+ @Test
+ public void testPositionLimitedAspectRatioNavBarLeft() throws Exception {
+ verifyPositionWithLimitedAspectRatio(NAV_BAR_LEFT, new Rect(0, 0, 2000, 1000), 1.5f,
+ new Rect(500, 0, 2000, 1000));
+ }
+
+ @Test
+ public void testPositionLimitedAspectRatioNavBarRight() throws Exception {
+ verifyPositionWithLimitedAspectRatio(NAV_BAR_RIGHT, new Rect(0, 0, 2000, 1000), 1.5f,
+ new Rect(0, 0, 1500, 1000));
+ }
+
+ private void verifyPositionWithLimitedAspectRatio(int navBarPosition, Rect taskBounds,
+ float aspectRatio, Rect expectedActivityBounds) {
+ final ActivityManagerService service = createActivityManagerService();
+ final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
+ final ActivityRecord record = createActivity(service, testActivityComponent, task);
+
+ // Verify with nav bar on the right.
+ when(service.mWindowManager.getNavBarPosition()).thenReturn(navBarPosition);
+ task.getConfiguration().setAppBounds(taskBounds);
+ record.info.maxAspectRatio = aspectRatio;
+ record.ensureActivityConfigurationLocked(0 /* globalChanges */, false /* preserveWindow */);
+ assertEquals(expectedActivityBounds, record.getBounds());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index bac1216..16bc011 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -120,6 +120,7 @@
null /*_taskDescription*/, new ActivityManager.TaskThumbnailInfo());
final ActivityStack stack = service.mStackSupervisor.getStack(stackId,
true /*createStaticStackIfNeeded*/, true /*onTop*/);
+ service.mStackSupervisor.setFocusStackUnchecked("test", stack);
stack.addTask(task, true, "creating test task");
task.setStack(stack);
task.setWindowContainerController(mock(TaskWindowContainerController.class));
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index a4e56fc..0a7a5f2 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -614,6 +615,11 @@
}
@Override
+ public int getNavBarPosition() {
+ return NAV_BAR_BOTTOM;
+ }
+
+ @Override
public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
Rect outInsets) {
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..d408b84 100644
--- a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
+++ b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
@@ -40,6 +40,31 @@
public class TonalTest {
@Test
+ public void extractInto_usesFallback() {
+ GradientColors normal = new GradientColors();
+ Tonal tonal = new Tonal();
+ 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();
+ 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, 0),
+ 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));
@@ -72,8 +97,10 @@
// 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);
+ assertFalse("Cannot generate a tonal palette from blacklisted colors.",
+ normal.getMainColor() == Tonal.MAIN_COLOR_LIGHT);
}
}
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 0dedf70..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,25 +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;
@@ -45,6 +58,8 @@
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
import org.junit.After;
import org.junit.Before;
@@ -63,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");
@@ -85,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 {
@@ -100,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);
@@ -113,7 +139,7 @@
}
@Test
- public void testNoSettingsValueDefaultEnabledDoesStart() {
+ public void testNoSettingsValueDefaultEnabledDoesStart() throws Exception {
setupFunctioningHardwareInterface();
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0);
try {
@@ -121,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);
@@ -134,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);
@@ -151,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);
@@ -171,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);
@@ -182,17 +204,43 @@
any(OffloadHardwareInterface.ControlCallback.class));
inOrder.verifyNoMoreInteractions();
- offload.setUpstreamLinkProperties(null);
- inOrder.verify(mHardware, times(1)).setUpstreamParameters(
- eq(null), eq(null), eq(null), eq(null));
+ // In reality, the UpstreamNetworkMonitor would have passed down to us
+ // a covering set of local prefixes representing a minimum essential
+ // set plus all the prefixes on networks with network agents.
+ //
+ // We simulate that there, and then add upstream elements one by one
+ // and watch what happens.
+ final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>();
+ for (String s : new String[]{
+ "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) {
+ minimumLocalPrefixes.add(new IpPrefix(s));
+ }
+ offload.setLocalPrefixes(minimumLocalPrefixes);
+ inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
+ ArrayList<String> localPrefixes = mStringArrayCaptor.getValue();
+ assertEquals(4, localPrefixes.size());
+ assertTrue(localPrefixes.contains("127.0.0.0/8"));
+ assertTrue(localPrefixes.contains("192.0.2.0/24"));
+ assertTrue(localPrefixes.contains("fe80::/64"));
+ assertTrue(localPrefixes.contains("2001:db8::/64"));
inOrder.verifyNoMoreInteractions();
- reset(mHardware);
+
+ offload.setUpstreamLinkProperties(null);
+ // No change in local addresses means no call to setLocalPrefixes().
+ inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
+ // This LinkProperties value does not differ from the default upstream.
+ // There should be no extraneous call to setUpstreamParameters().
+ inOrder.verify(mHardware, never()).setUpstreamParameters(
+ anyObject(), anyObject(), anyObject(), anyObject());
+ inOrder.verifyNoMoreInteractions();
final LinkProperties lp = new LinkProperties();
final String testIfName = "rmnet_data17";
lp.setInterfaceName(testIfName);
offload.setUpstreamLinkProperties(lp);
+ // No change in local addresses means no call to setLocalPrefixes().
+ inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(null), eq(null), eq(null));
inOrder.verifyNoMoreInteractions();
@@ -200,23 +248,38 @@
final String ipv4Addr = "192.0.2.5";
final String linkAddr = ipv4Addr + "/24";
lp.addLinkAddress(new LinkAddress(linkAddr));
+ lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24")));
offload.setUpstreamLinkProperties(lp);
+ // IPv4 prefixes and addresses on the upstream are simply left as whole
+ // prefixes (already passed in from UpstreamNetworkMonitor code). If a
+ // tethering client sends traffic to the IPv4 default router or other
+ // clients on the upstream this will not be hardware-forwarded, and that
+ // should be fine for now. Ergo: no change in local addresses, no call
+ // to setLocalPrefixes().
+ 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";
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway)));
offload.setUpstreamLinkProperties(lp);
+ // No change in local addresses means no call to setLocalPrefixes().
+ 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";
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1)));
offload.setUpstreamLinkProperties(lp);
+ // No change in local addresses means no call to setLocalPrefixes().
+ 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));
@@ -225,8 +288,11 @@
final String ipv6Gw2 = "fe80::d00d";
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2)));
offload.setUpstreamLinkProperties(lp);
+ // No change in local addresses means no call to setLocalPrefixes().
+ 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));
@@ -240,12 +306,115 @@
stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00")));
assertTrue(lp.addStackedLink(stacked));
offload.setUpstreamLinkProperties(lp);
+ // No change in local addresses means no call to setLocalPrefixes().
+ 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));
+ assertTrue(v6gws.contains(ipv6Gw2));
+ inOrder.verifyNoMoreInteractions();
+
+ // Add in some IPv6 upstream info. When there is a tethered downstream
+ // making use of the IPv6 prefix we would expect to see the /64 route
+ // removed from "local prefixes" and /128s added for the upstream IPv6
+ // addresses. This is not yet implemented, and for now we simply
+ // expect to see these /128s.
+ lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64")));
+ // "2001:db8::/64" plus "assigned" ASCII in hex
+ lp.addLinkAddress(new LinkAddress("2001:db8::6173:7369:676e:6564/64"));
+ // "2001:db8::/64" plus "random" ASCII in hex
+ lp.addLinkAddress(new LinkAddress("2001:db8::7261:6e64:6f6d/64"));
+ offload.setUpstreamLinkProperties(lp);
+ inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
+ localPrefixes = mStringArrayCaptor.getValue();
+ assertEquals(6, localPrefixes.size());
+ assertTrue(localPrefixes.contains("127.0.0.0/8"));
+ assertTrue(localPrefixes.contains("192.0.2.0/24"));
+ assertTrue(localPrefixes.contains("fe80::/64"));
+ assertTrue(localPrefixes.contains("2001:db8::/64"));
+ assertTrue(localPrefixes.contains("2001:db8::6173:7369:676e:6564/128"));
+ assertTrue(localPrefixes.contains("2001:db8::7261:6e64:6f6d/128"));
+ // The relevant parts of the LinkProperties have not changed, but at the
+ // moment we do not de-dup upstream LinkProperties this carefully.
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
v6gws = mStringArrayCaptor.getValue();
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.
+ offload.setUpstreamLinkProperties(lp);
+ // This LinkProperties value does not differ from the default upstream.
+ // There should be no extraneous call to setUpstreamParameters().
+ inOrder.verify(mHardware, never()).setUpstreamParameters(
+ 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);
}
}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index 69c93b1..c3b9def 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -324,19 +324,14 @@
}
@Test
- public void testOffloadExemptPrefixes() throws Exception {
+ public void testLocalPrefixes() throws Exception {
mUNM.start();
- // [0] Test minimum set of exempt prefixes.
- Set<IpPrefix> exempt = mUNM.getOffloadExemptPrefixes();
- final String[] MINSET = {
- "127.0.0.0/8", "169.254.0.0/16",
- "::/3", "fe80::/64", "fc00::/7", "ff00::/8",
- };
- assertPrefixSet(exempt, INCLUDES, MINSET);
+ // [0] Test minimum set of local prefixes.
+ Set<IpPrefix> local = mUNM.getLocalPrefixes();
+ assertTrue(local.isEmpty());
+
final Set<String> alreadySeen = new HashSet<>();
- Collections.addAll(alreadySeen, MINSET);
- assertEquals(alreadySeen.size(), exempt.size());
// [1] Pretend Wi-Fi connects.
final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
@@ -355,15 +350,15 @@
wifiAgent.fakeConnect();
wifiAgent.sendLinkProperties(wifiLp);
- exempt = mUNM.getOffloadExemptPrefixes();
- assertPrefixSet(exempt, INCLUDES, alreadySeen);
+ local = mUNM.getLocalPrefixes();
+ assertPrefixSet(local, INCLUDES, alreadySeen);
final String[] wifiLinkPrefixes = {
- // Excludes link-local as that's already tested within MINSET.
+ // Link-local prefixes are excluded and dealt with elsewhere.
"100.112.96.0/20", "2001:db8:4:fd00::/64", "fd6a:a640:60bf:e985::/64",
};
- assertPrefixSet(exempt, INCLUDES, wifiLinkPrefixes);
+ assertPrefixSet(local, INCLUDES, wifiLinkPrefixes);
Collections.addAll(alreadySeen, wifiLinkPrefixes);
- assertEquals(alreadySeen.size(), exempt.size());
+ assertEquals(alreadySeen.size(), local.size());
// [2] Pretend mobile connects.
final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
@@ -379,12 +374,12 @@
cellAgent.fakeConnect();
cellAgent.sendLinkProperties(cellLp);
- exempt = mUNM.getOffloadExemptPrefixes();
- assertPrefixSet(exempt, INCLUDES, alreadySeen);
+ local = mUNM.getLocalPrefixes();
+ assertPrefixSet(local, INCLUDES, alreadySeen);
final String[] cellLinkPrefixes = { "10.102.211.32/27", "2001:db8:0:1::/64" };
- assertPrefixSet(exempt, INCLUDES, cellLinkPrefixes);
+ assertPrefixSet(local, INCLUDES, cellLinkPrefixes);
Collections.addAll(alreadySeen, cellLinkPrefixes);
- assertEquals(alreadySeen.size(), exempt.size());
+ assertEquals(alreadySeen.size(), local.size());
// [3] Pretend DUN connects.
final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
@@ -401,21 +396,20 @@
dunAgent.fakeConnect();
dunAgent.sendLinkProperties(dunLp);
- exempt = mUNM.getOffloadExemptPrefixes();
- assertPrefixSet(exempt, INCLUDES, alreadySeen);
+ local = mUNM.getLocalPrefixes();
+ assertPrefixSet(local, INCLUDES, alreadySeen);
final String[] dunLinkPrefixes = { "192.0.2.32/27", "2001:db8:1:2::/64" };
- assertPrefixSet(exempt, INCLUDES, dunLinkPrefixes);
+ assertPrefixSet(local, INCLUDES, dunLinkPrefixes);
Collections.addAll(alreadySeen, dunLinkPrefixes);
- assertEquals(alreadySeen.size(), exempt.size());
+ assertEquals(alreadySeen.size(), local.size());
// [4] Pretend Wi-Fi disconnected. It's addresses/prefixes should no
// longer be included (should be properly removed).
wifiAgent.fakeDisconnect();
- exempt = mUNM.getOffloadExemptPrefixes();
- assertPrefixSet(exempt, INCLUDES, MINSET);
- assertPrefixSet(exempt, EXCLUDES, wifiLinkPrefixes);
- assertPrefixSet(exempt, INCLUDES, cellLinkPrefixes);
- assertPrefixSet(exempt, INCLUDES, dunLinkPrefixes);
+ local = mUNM.getLocalPrefixes();
+ assertPrefixSet(local, EXCLUDES, wifiLinkPrefixes);
+ assertPrefixSet(local, INCLUDES, cellLinkPrefixes);
+ assertPrefixSet(local, INCLUDES, dunLinkPrefixes);
}
private void assertSatisfiesLegacyType(int legacyType, NetworkState ns) {