diff options
104 files changed, 2712 insertions, 1220 deletions
diff --git a/api/current.txt b/api/current.txt index 14fb7dd28244..7979d916bbd7 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2216,34 +2216,34 @@ package android { field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d field public static final int Theme_Dialog = 16973835; // 0x103000b - field public static final int Theme_Holo = 16973931; // 0x103006b - field public static final int Theme_Holo_Dialog = 16973935; // 0x103006f - field public static final int Theme_Holo_DialogWhenLarge = 16973943; // 0x1030077 - field public static final int Theme_Holo_DialogWhenLarge_NoActionBar = 16973944; // 0x1030078 - field public static final int Theme_Holo_Dialog_MinWidth = 16973936; // 0x1030070 - field public static final int Theme_Holo_Dialog_NoActionBar = 16973937; // 0x1030071 - field public static final int Theme_Holo_Dialog_NoActionBar_MinWidth = 16973938; // 0x1030072 - field public static final int Theme_Holo_InputMethod = 16973951; // 0x103007f - field public static final int Theme_Holo_Light = 16973934; // 0x103006e - field public static final int Theme_Holo_Light_DarkActionBar = 16974105; // 0x1030119 - field public static final int Theme_Holo_Light_Dialog = 16973939; // 0x1030073 - field public static final int Theme_Holo_Light_DialogWhenLarge = 16973945; // 0x1030079 - field public static final int Theme_Holo_Light_DialogWhenLarge_NoActionBar = 16973946; // 0x103007a - field public static final int Theme_Holo_Light_Dialog_MinWidth = 16973940; // 0x1030074 - field public static final int Theme_Holo_Light_Dialog_NoActionBar = 16973941; // 0x1030075 - field public static final int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076 - field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0 - field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1 - field public static final int Theme_Holo_Light_NoActionBar_Overscan = 16974302; // 0x10301de - field public static final int Theme_Holo_Light_NoActionBar_TranslucentDecor = 16974306; // 0x10301e2 - field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c - field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c - field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d - field public static final int Theme_Holo_NoActionBar_Overscan = 16974301; // 0x10301dd - field public static final int Theme_Holo_NoActionBar_TranslucentDecor = 16974305; // 0x10301e1 - field public static final int Theme_Holo_Panel = 16973947; // 0x103007b - field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d - field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e + field public static final deprecated int Theme_Holo = 16973931; // 0x103006b + field public static final deprecated int Theme_Holo_Dialog = 16973935; // 0x103006f + field public static final deprecated int Theme_Holo_DialogWhenLarge = 16973943; // 0x1030077 + field public static final deprecated int Theme_Holo_DialogWhenLarge_NoActionBar = 16973944; // 0x1030078 + field public static final deprecated int Theme_Holo_Dialog_MinWidth = 16973936; // 0x1030070 + field public static final deprecated int Theme_Holo_Dialog_NoActionBar = 16973937; // 0x1030071 + field public static final deprecated int Theme_Holo_Dialog_NoActionBar_MinWidth = 16973938; // 0x1030072 + field public static final deprecated int Theme_Holo_InputMethod = 16973951; // 0x103007f + field public static final deprecated int Theme_Holo_Light = 16973934; // 0x103006e + field public static final deprecated int Theme_Holo_Light_DarkActionBar = 16974105; // 0x1030119 + field public static final deprecated int Theme_Holo_Light_Dialog = 16973939; // 0x1030073 + field public static final deprecated int Theme_Holo_Light_DialogWhenLarge = 16973945; // 0x1030079 + field public static final deprecated int Theme_Holo_Light_DialogWhenLarge_NoActionBar = 16973946; // 0x103007a + field public static final deprecated int Theme_Holo_Light_Dialog_MinWidth = 16973940; // 0x1030074 + field public static final deprecated int Theme_Holo_Light_Dialog_NoActionBar = 16973941; // 0x1030075 + field public static final deprecated int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076 + field public static final deprecated int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0 + field public static final deprecated int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1 + field public static final deprecated int Theme_Holo_Light_NoActionBar_Overscan = 16974302; // 0x10301de + field public static final deprecated int Theme_Holo_Light_NoActionBar_TranslucentDecor = 16974306; // 0x10301e2 + field public static final deprecated int Theme_Holo_Light_Panel = 16973948; // 0x103007c + field public static final deprecated int Theme_Holo_NoActionBar = 16973932; // 0x103006c + field public static final deprecated int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d + field public static final deprecated int Theme_Holo_NoActionBar_Overscan = 16974301; // 0x10301dd + field public static final deprecated int Theme_Holo_NoActionBar_TranslucentDecor = 16974305; // 0x10301e1 + field public static final deprecated int Theme_Holo_Panel = 16973947; // 0x103007b + field public static final deprecated int Theme_Holo_Wallpaper = 16973949; // 0x103007d + field public static final deprecated int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e field public static final int Theme_InputMethod = 16973908; // 0x1030054 field public static final int Theme_Light = 16973836; // 0x103000c field public static final int Theme_Light_NoTitleBar = 16973837; // 0x103000d @@ -28509,29 +28509,6 @@ package android.net.wifi.p2p.nsd { package android.net.wifi.rtt { - public final class LocationCivic implements android.os.Parcelable { - method public int describeContents(); - method public byte[] getData(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.net.wifi.rtt.LocationCivic> CREATOR; - } - - public final class LocationConfigurationInformation implements android.os.Parcelable { - method public int describeContents(); - method public double getAltitude(); - method public int getAltitudeType(); - method public double getAltitudeUncertainty(); - method public double getLatitude(); - method public double getLatitudeUncertainty(); - method public double getLongitude(); - method public double getLongitudeUncertainty(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int ALTITUDE_IN_FLOORS = 2; // 0x2 - field public static final int ALTITUDE_IN_METERS = 1; // 0x1 - field public static final int ALTITUDE_UNKNOWN = 0; // 0x0 - field public static final android.os.Parcelable.Creator<android.net.wifi.rtt.LocationConfigurationInformation> CREATOR; - } - public final class RangingRequest implements android.os.Parcelable { method public int describeContents(); method public static int getMaxPeers(); @@ -28555,8 +28532,6 @@ package android.net.wifi.rtt { method public android.net.MacAddress getMacAddress(); method public android.net.wifi.aware.PeerHandle getPeerHandle(); method public long getRangingTimestampUs(); - method public android.net.wifi.rtt.LocationCivic getReportedLocationCivic(); - method public android.net.wifi.rtt.LocationConfigurationInformation getReportedLocationConfigurationInformation(); method public int getRssi(); method public int getStatus(); method public void writeToParcel(android.os.Parcel, int); @@ -33037,14 +33012,14 @@ package android.os { } public final class SystemClock { + method public static java.time.Clock currentNetworkTimeClock(); + method public static long currentNetworkTimeMillis(); method public static long currentThreadTimeMillis(); method public static long elapsedRealtime(); - method public static java.time.Clock elapsedRealtimeClock(); method public static long elapsedRealtimeNanos(); method public static boolean setCurrentTimeMillis(long); method public static void sleep(long); method public static long uptimeMillis(); - method public static java.time.Clock uptimeMillisClock(); } public class TestLooperManager { @@ -44496,10 +44471,12 @@ package android.text.style { public class TypefaceSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan { ctor public TypefaceSpan(java.lang.String); + ctor public TypefaceSpan(android.graphics.Typeface); ctor public TypefaceSpan(android.os.Parcel); method public int describeContents(); method public java.lang.String getFamily(); method public int getSpanTypeId(); + method public android.graphics.Typeface getTypeface(); method public void updateDrawState(android.text.TextPaint); method public void updateMeasureState(android.text.TextPaint); method public void writeToParcel(android.os.Parcel, int); diff --git a/api/removed.txt b/api/removed.txt index 2aab223ed281..55022f36a016 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -257,6 +257,12 @@ package android.os { ctor public RecoverySystem(); } + public final class SystemClock { + method public static java.time.Clock elapsedRealtimeClock(); + method public static java.time.Clock uptimeClock(); + method public static deprecated java.time.Clock uptimeMillisClock(); + } + public class TestLooperManager { method public deprecated android.os.MessageQueue getQueue(); } diff --git a/api/system-current.txt b/api/system-current.txt index 8001ee3b7f6d..affaf0de2094 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3524,6 +3524,11 @@ package android.net.wifi.rtt { method public android.net.wifi.rtt.RangingRequest.Builder addResponder(android.net.wifi.rtt.ResponderConfig); } + public final class RangingResult implements android.os.Parcelable { + method public byte[] getLci(); + method public byte[] getLcr(); + } + public final class ResponderConfig implements android.os.Parcelable { ctor public ResponderConfig(android.net.MacAddress, int, boolean, int, int, int, int, int); ctor public ResponderConfig(android.net.wifi.aware.PeerHandle, int, boolean, int, int, int, int, int); diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp index 08c59cfed518..bee99396126d 100644 --- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp +++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp @@ -115,7 +115,10 @@ const std::map<int, PullAtomInfo> StatsPullerManagerImpl::kAllPullAtomInfo = { {{}, {}, 1, new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}}, // full_battery_capacity {android::util::FULL_BATTERY_CAPACITY, - {{}, {}, 1, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}}; + {{}, {}, 1, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}, + // process_memory_state + {android::util::PROCESS_MEMORY_STATE, + {{4,5,6,7,8}, {2,3}, 0, new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}}; StatsPullerManagerImpl::StatsPullerManagerImpl() : mCurrentPullingInterval(LONG_MAX) { diff --git a/core/java/android/annotation/RequiresFeature.java b/core/java/android/annotation/RequiresFeature.java new file mode 100644 index 000000000000..fc93f03d76cf --- /dev/null +++ b/core/java/android/annotation/RequiresFeature.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.annotation; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.content.pm.PackageManager; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Denotes that the annotated element requires one or more device features. This + * is used to auto-generate documentation. + * + * @see PackageManager#hasSystemFeature(String) + * @hide + */ +@Retention(SOURCE) +@Target({TYPE,FIELD,METHOD,CONSTRUCTOR}) +public @interface RequiresFeature { + /** + * The name of the device feature that is required. + * + * @see PackageManager#hasSystemFeature(String) + */ + String value(); +} diff --git a/core/java/android/annotation/SystemService.java b/core/java/android/annotation/SystemService.java index ba5002a4f1b5..0c5d15e178a3 100644 --- a/core/java/android/annotation/SystemService.java +++ b/core/java/android/annotation/SystemService.java @@ -26,12 +26,19 @@ import java.lang.annotation.Target; /** * Description of a system service available through - * {@link Context#getSystemService(Class)}. + * {@link Context#getSystemService(Class)}. This is used to auto-generate + * documentation explaining how to obtain a reference to the service. * * @hide */ @Retention(SOURCE) @Target(TYPE) public @interface SystemService { + /** + * The string name of the system service that can be passed to + * {@link Context#getSystemService(String)}. + * + * @see Context#getSystemServiceName(Class) + */ String value(); } diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index b365d52313ca..0c98267cfd68 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -356,4 +356,9 @@ public abstract class ActivityManagerInternal { * Whether an UID is active or idle. */ public abstract boolean isUidActive(int uid); + + /** + * Returns a list that contains the memory stats for currently running processes. + */ + public abstract List<ProcessMemoryState> getMemoryStateForProcesses(); } diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index f6e5f373ba46..54fd0c45a811 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -686,24 +686,24 @@ interface IActivityManager { // If a transaction which will also be used on the native side is being inserted, add it // alongside with other transactions of this kind at the top of this file. - void setShowWhenLocked(in IBinder token, boolean showWhenLocked); - void setTurnScreenOn(in IBinder token, boolean turnScreenOn); - - /** - * Similar to {@link #startUserInBackground(int userId), but with a listener to report - * user unlock progress. - */ - boolean startUserInBackgroundWithListener(int userid, IProgressListener unlockProgressListener); - - /** - * Registers remote animations for a specific activity. - */ - void registerRemoteAnimations(in IBinder token, in RemoteAnimationDefinition definition); - - /** - * Registers a remote animation to be run for all activity starts from a certain package during - * a short predefined amount of time. - */ - void registerRemoteAnimationForNextActivityStart(in String packageName, - in RemoteAnimationAdapter adapter); + void setShowWhenLocked(in IBinder token, boolean showWhenLocked); + void setTurnScreenOn(in IBinder token, boolean turnScreenOn); + + /** + * Similar to {@link #startUserInBackground(int userId), but with a listener to report + * user unlock progress. + */ + boolean startUserInBackgroundWithListener(int userid, IProgressListener unlockProgressListener); + + /** + * Registers remote animations for a specific activity. + */ + void registerRemoteAnimations(in IBinder token, in RemoteAnimationDefinition definition); + + /** + * Registers a remote animation to be run for all activity starts from a certain package during + * a short predefined amount of time. + */ + void registerRemoteAnimationForNextActivityStart(in String packageName, + in RemoteAnimationAdapter adapter); } diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl index 7b05b4918103..ded4c4954956 100644 --- a/core/java/android/app/IAlarmManager.aidl +++ b/core/java/android/app/IAlarmManager.aidl @@ -37,4 +37,5 @@ interface IAlarmManager { void remove(in PendingIntent operation, in IAlarmListener listener); long getNextWakeFromIdleTime(); AlarmManager.AlarmClockInfo getNextAlarmClock(int userId); + long currentNetworkTimeMillis(); } diff --git a/core/java/android/app/ProcessMemoryState.java b/core/java/android/app/ProcessMemoryState.java new file mode 100644 index 000000000000..39db16d10575 --- /dev/null +++ b/core/java/android/app/ProcessMemoryState.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * The memory stats for a process. + * {@hide} + */ +public class ProcessMemoryState implements Parcelable { + public int uid; + public String processName; + public int oomScore; + public long pgfault; + public long pgmajfault; + public long rssInBytes; + public long cacheInBytes; + public long swapInBytes; + + public ProcessMemoryState(int uid, String processName, int oomScore, long pgfault, + long pgmajfault, long rssInBytes, long cacheInBytes, + long swapInBytes) { + this.uid = uid; + this.processName = processName; + this.oomScore = oomScore; + this.pgfault = pgfault; + this.pgmajfault = pgmajfault; + this.rssInBytes = rssInBytes; + this.cacheInBytes = cacheInBytes; + this.swapInBytes = swapInBytes; + } + + private ProcessMemoryState(Parcel in) { + uid = in.readInt(); + processName = in.readString(); + oomScore = in.readInt(); + pgfault = in.readLong(); + pgmajfault = in.readLong(); + rssInBytes = in.readLong(); + cacheInBytes = in.readLong(); + swapInBytes = in.readLong(); + } + + public static final Creator<ProcessMemoryState> CREATOR = new Creator<ProcessMemoryState>() { + @Override + public ProcessMemoryState createFromParcel(Parcel in) { + return new ProcessMemoryState(in); + } + + @Override + public ProcessMemoryState[] newArray(int size) { + return new ProcessMemoryState[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeInt(uid); + parcel.writeString(processName); + parcel.writeInt(oomScore); + parcel.writeLong(pgfault); + parcel.writeLong(pgmajfault); + parcel.writeLong(rssInBytes); + parcel.writeLong(cacheInBytes); + parcel.writeLong(swapInBytes); + } +} diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index b29644bcf320..14b2119b4e4b 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -21,6 +21,7 @@ import android.annotation.ColorInt; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -116,6 +117,7 @@ import java.util.concurrent.Executor; * guide. </div> */ @SystemService(Context.DEVICE_POLICY_SERVICE) +@RequiresFeature(PackageManager.FEATURE_DEVICE_ADMIN) public class DevicePolicyManager { private static String TAG = "DevicePolicyManager"; diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index a2c75a6c014c..e736f34eea11 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -19,6 +19,7 @@ package android.appwidget; import android.annotation.BroadcastBehavior; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; @@ -29,6 +30,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.ServiceConnection; +import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.os.Bundle; @@ -55,6 +57,7 @@ import java.util.List; * </div> */ @SystemService(Context.APPWIDGET_SERVICE) +@RequiresFeature(PackageManager.FEATURE_APP_WIDGETS) public class AppWidgetManager { /** diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java index 7e3bb05fe024..11f8ab7551c2 100644 --- a/core/java/android/bluetooth/BluetoothManager.java +++ b/core/java/android/bluetooth/BluetoothManager.java @@ -17,9 +17,11 @@ package android.bluetooth; import android.Manifest; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.content.Context; +import android.content.pm.PackageManager; import android.os.RemoteException; import android.util.Log; @@ -47,6 +49,7 @@ import java.util.List; * @see BluetoothAdapter#getDefaultAdapter() */ @SystemService(Context.BLUETOOTH_SERVICE) +@RequiresFeature(PackageManager.FEATURE_BLUETOOTH) public final class BluetoothManager { private static final String TAG = "BluetoothManager"; private static final boolean DBG = true; diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl index 86c1aa8228f1..5b3c9dd93370 100644 --- a/core/java/android/content/om/IOverlayManager.aidl +++ b/core/java/android/content/om/IOverlayManager.aidl @@ -83,17 +83,36 @@ interface IOverlayManager { * @param packageName The name of the overlay package. * @param enable true to enable the overlay, false to disable it. * @param userId The user for which to change the overlay. - * @return true if the system successfully registered the request, false - * otherwise. + * @return true if the system successfully registered the request, false otherwise. */ boolean setEnabled(in String packageName, in boolean enable, in int userId); /** - * Version of setEnabled that will also disable any other overlays for the target package. + * Request that an overlay package is enabled and any other overlay packages with the same + * target package are disabled. + * + * See {@link #setEnabled} for the details on overlay packages. + * + * @param packageName the name of the overlay package to enable. + * @param enabled must be true, otherwise the operation fails. + * @param userId The user for which to change the overlay. + * @return true if the system successfully registered the request, false otherwise. */ boolean setEnabledExclusive(in String packageName, in boolean enable, in int userId); /** + * Request that an overlay package is enabled and any other overlay packages with the same + * target package and category are disabled. + * + * See {@link #setEnabled} for the details on overlay packages. + * + * @param packageName the name of the overlay package to enable. + * @param userId The user for which to change the overlay. + * @return true if the system successfully registered the request, false otherwise. + */ + boolean setEnabledExclusiveInCategory(in String packageName, in int userId); + + /** * Change the priority of the given overlay to be just higher than the * overlay with package name newParentPackageName. Both overlay packages * must have the same target and user. diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java index 8464e26ec6cd..6e63342698b3 100644 --- a/core/java/android/content/om/OverlayInfo.java +++ b/core/java/android/content/om/OverlayInfo.java @@ -18,6 +18,7 @@ package android.content.om; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; @@ -66,14 +67,14 @@ public final class OverlayInfo implements Parcelable { /** * The overlay is currently disabled. It can be enabled. * - * @see IOverlayManager.setEnabled + * @see IOverlayManager#setEnabled */ public static final int STATE_DISABLED = 2; /** * The overlay is currently enabled. It can be disabled. * - * @see IOverlayManager.setEnabled + * @see IOverlayManager#setEnabled */ public static final int STATE_ENABLED = 3; @@ -90,6 +91,11 @@ public final class OverlayInfo implements Parcelable { public static final int STATE_OVERLAY_UPGRADING = 5; /** + * Category for theme overlays. + */ + public static final String CATEGORY_THEME = "android.theme"; + + /** * Package name of the overlay package */ public final String packageName; @@ -100,6 +106,11 @@ public final class OverlayInfo implements Parcelable { public final String targetPackageName; /** + * Category of the overlay package + */ + public final String category; + + /** * Full path to the base APK for this overlay package */ public final String baseCodePath; @@ -121,14 +132,15 @@ public final class OverlayInfo implements Parcelable { * @param state the new state for the source OverlayInfo */ public OverlayInfo(@NonNull OverlayInfo source, @State int state) { - this(source.packageName, source.targetPackageName, source.baseCodePath, state, - source.userId); + this(source.packageName, source.targetPackageName, source.category, source.baseCodePath, + state, source.userId); } public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName, - @NonNull String baseCodePath, @State int state, int userId) { + @Nullable String category, @NonNull String baseCodePath, int state, int userId) { this.packageName = packageName; this.targetPackageName = targetPackageName; + this.category = category; this.baseCodePath = baseCodePath; this.state = state; this.userId = userId; @@ -138,6 +150,7 @@ public final class OverlayInfo implements Parcelable { public OverlayInfo(Parcel source) { packageName = source.readString(); targetPackageName = source.readString(); + category = source.readString(); baseCodePath = source.readString(); state = source.readInt(); userId = source.readInt(); @@ -177,6 +190,7 @@ public final class OverlayInfo implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(packageName); dest.writeString(targetPackageName); + dest.writeString(category); dest.writeString(baseCodePath); dest.writeInt(state); dest.writeInt(userId); @@ -275,6 +289,9 @@ public final class OverlayInfo implements Parcelable { if (!targetPackageName.equals(other.targetPackageName)) { return false; } + if (!category.equals(other.category)) { + return false; + } if (!baseCodePath.equals(other.baseCodePath)) { return false; } diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index 0342c93bb34f..627ceb7871f2 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -362,6 +362,13 @@ public class PackageInfo implements Parcelable { */ public String overlayTarget; + /** + * The overlay category, if any, of this package + * + * @hide + */ + public String overlayCategory; + /** @hide */ public int overlayPriority; @@ -464,6 +471,7 @@ public class PackageInfo implements Parcelable { dest.writeString(restrictedAccountType); dest.writeString(requiredAccountType); dest.writeString(overlayTarget); + dest.writeString(overlayCategory); dest.writeInt(overlayPriority); dest.writeBoolean(mOverlayIsStatic); dest.writeInt(compileSdkVersion); @@ -531,6 +539,7 @@ public class PackageInfo implements Parcelable { restrictedAccountType = source.readString(); requiredAccountType = source.readString(); overlayTarget = source.readString(); + overlayCategory = source.readString(); overlayPriority = source.readInt(); mOverlayIsStatic = source.readBoolean(); compileSdkVersion = source.readInt(); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index dda4167d3c3b..9e4166eaec1b 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -676,6 +676,7 @@ public class PackageParser { pi.restrictedAccountType = p.mRestrictedAccountType; pi.requiredAccountType = p.mRequiredAccountType; pi.overlayTarget = p.mOverlayTarget; + pi.overlayCategory = p.mOverlayCategory; pi.overlayPriority = p.mOverlayPriority; pi.mOverlayIsStatic = p.mOverlayIsStatic; pi.compileSdkVersion = p.mCompileSdkVersion; @@ -2073,6 +2074,8 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestResourceOverlay); pkg.mOverlayTarget = sa.getString( com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage); + pkg.mOverlayCategory = sa.getString( + com.android.internal.R.styleable.AndroidManifestResourceOverlay_category); pkg.mOverlayPriority = sa.getInt( com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority, 0); @@ -6324,6 +6327,7 @@ public class PackageParser { public String mRequiredAccountType; public String mOverlayTarget; + public String mOverlayCategory; public int mOverlayPriority; public boolean mOverlayIsStatic; @@ -6834,6 +6838,7 @@ public class PackageParser { mRestrictedAccountType = dest.readString(); mRequiredAccountType = dest.readString(); mOverlayTarget = dest.readString(); + mOverlayCategory = dest.readString(); mOverlayPriority = dest.readInt(); mOverlayIsStatic = (dest.readInt() == 1); mCompileSdkVersion = dest.readInt(); @@ -6957,6 +6962,7 @@ public class PackageParser { dest.writeString(mRestrictedAccountType); dest.writeString(mRequiredAccountType); dest.writeString(mOverlayTarget); + dest.writeString(mOverlayCategory); dest.writeInt(mOverlayPriority); dest.writeInt(mOverlayIsStatic ? 1 : 0); dest.writeInt(mCompileSdkVersion); diff --git a/core/java/android/hardware/ConsumerIrManager.java b/core/java/android/hardware/ConsumerIrManager.java index c7a33ffa1b0f..6f589cd9190b 100644 --- a/core/java/android/hardware/ConsumerIrManager.java +++ b/core/java/android/hardware/ConsumerIrManager.java @@ -16,8 +16,10 @@ package android.hardware; +import android.annotation.RequiresFeature; import android.annotation.SystemService; import android.content.Context; +import android.content.pm.PackageManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; @@ -27,6 +29,7 @@ import android.util.Log; * Class that operates consumer infrared on the device. */ @SystemService(Context.CONSUMER_IR_SERVICE) +@RequiresFeature(PackageManager.FEATURE_CONSUMER_IR) public final class ConsumerIrManager { private static final String TAG = "ConsumerIr"; diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 92d6bbb0a20f..bd54522719b2 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -23,10 +23,12 @@ import static android.Manifest.permission.USE_FINGERPRINT; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.app.ActivityManager; import android.content.Context; +import android.content.pm.PackageManager; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricFingerprintConstants; import android.os.Binder; @@ -59,6 +61,7 @@ import javax.crypto.Mac; */ @Deprecated @SystemService(Context.FINGERPRINT_SERVICE) +@RequiresFeature(PackageManager.FEATURE_FINGERPRINT) public class FingerprintManager implements BiometricFingerprintConstants { private static final String TAG = "FingerprintManager"; private static final boolean DEBUG = true; diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index a772cbe43196..e34423c05a87 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -17,11 +17,13 @@ package android.hardware.hdmi; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SuppressLint; import android.content.Context; +import android.content.pm.PackageManager; import android.annotation.SystemApi; import android.annotation.SystemService; import android.os.RemoteException; @@ -42,6 +44,7 @@ import android.util.Log; */ @SystemApi @SystemService(Context.HDMI_CONTROL_SERVICE) +@RequiresFeature(PackageManager.FEATURE_HDMI_CEC) public final class HdmiControlManager { private static final String TAG = "HdmiControlManager"; diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java index e1d7edfa7d9c..8fde82ef2012 100644 --- a/core/java/android/hardware/radio/RadioManager.java +++ b/core/java/android/hardware/radio/RadioManager.java @@ -21,10 +21,12 @@ import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; @@ -58,6 +60,7 @@ import java.util.stream.Collectors; */ @SystemApi @SystemService(Context.RADIO_SERVICE) +@RequiresFeature(PackageManager.FEATURE_BROADCAST_RADIO) public class RadioManager { private static final String TAG = "BroadcastRadio.manager"; diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index 8daecac5a109..74a36df03b00 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -19,6 +19,7 @@ package android.hardware.usb; import android.Manifest; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -27,6 +28,7 @@ import android.annotation.SystemService; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.hardware.usb.gadget.V1_0.GadgetFunction; import android.os.Bundle; @@ -382,6 +384,7 @@ public class UsbManager { * * @return HashMap containing all connected USB devices. */ + @RequiresFeature(PackageManager.FEATURE_USB_HOST) public HashMap<String,UsbDevice> getDeviceList() { HashMap<String,UsbDevice> result = new HashMap<String,UsbDevice>(); if (mService == null) { @@ -406,6 +409,7 @@ public class UsbManager { * @param device the device to open * @return a {@link UsbDeviceConnection}, or {@code null} if open failed */ + @RequiresFeature(PackageManager.FEATURE_USB_HOST) public UsbDeviceConnection openDevice(UsbDevice device) { try { String deviceName = device.getDeviceName(); @@ -430,6 +434,7 @@ public class UsbManager { * * @return list of USB accessories, or null if none are attached. */ + @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY) public UsbAccessory[] getAccessoryList() { if (mService == null) { return null; @@ -452,6 +457,7 @@ public class UsbManager { * @param accessory the USB accessory to open * @return file descriptor, or null if the accessor could not be opened. */ + @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY) public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { try { return mService.openAccessory(accessory); @@ -472,6 +478,7 @@ public class UsbManager { * @param device to check permissions for * @return true if caller has permission */ + @RequiresFeature(PackageManager.FEATURE_USB_HOST) public boolean hasPermission(UsbDevice device) { if (mService == null) { return false; @@ -492,6 +499,7 @@ public class UsbManager { * @param accessory to check permissions for * @return true if caller has permission */ + @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY) public boolean hasPermission(UsbAccessory accessory) { if (mService == null) { return false; @@ -525,6 +533,7 @@ public class UsbManager { * @param device to request permissions for * @param pi PendingIntent for returning result */ + @RequiresFeature(PackageManager.FEATURE_USB_HOST) public void requestPermission(UsbDevice device, PendingIntent pi) { try { mService.requestDevicePermission(device, mContext.getPackageName(), pi); @@ -551,6 +560,7 @@ public class UsbManager { * @param accessory to request permissions for * @param pi PendingIntent for returning result */ + @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY) public void requestPermission(UsbAccessory accessory, PendingIntent pi) { try { mService.requestAccessoryPermission(accessory, mContext.getPackageName(), pi); diff --git a/core/java/android/os/BestClock.java b/core/java/android/os/BestClock.java new file mode 100644 index 000000000000..aa066b633e6b --- /dev/null +++ b/core/java/android/os/BestClock.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.util.Log; + +import java.time.Clock; +import java.time.DateTimeException; +import java.time.ZoneId; +import java.util.Arrays; + +/** + * Single {@link Clock} that will return the best available time from a set of + * prioritized {@link Clock} instances. + * <p> + * For example, when {@link SystemClock#currentNetworkTimeClock()} isn't able to + * provide the time, this class could use {@link Clock#systemUTC()} instead. + * + * @hide + */ +public class BestClock extends SimpleClock { + private static final String TAG = "BestClock"; + + private final Clock[] clocks; + + public BestClock(ZoneId zone, Clock... clocks) { + super(zone); + this.clocks = clocks; + } + + @Override + public long millis() { + for (Clock clock : clocks) { + try { + return clock.millis(); + } catch (DateTimeException e) { + // Ignore and attempt the next clock + Log.w(TAG, e.toString()); + } + } + throw new DateTimeException( + "No clocks in " + Arrays.toString(clocks) + " were able to provide time"); + } +} diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 682fdb7160f4..ff7c0c6681c6 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -1028,22 +1028,33 @@ final class BinderProxy implements IBinder { * in use, then we return the same bp. * * @param nativeData C++ pointer to (possibly still empty) BinderProxyNativeData. - * Takes ownership of nativeData iff <result>.mNativeData == nativeData. Caller will usually - * delete nativeData if that's not the case. + * Takes ownership of nativeData iff <result>.mNativeData == nativeData, or if + * we exit via an exception. If neither applies, it's the callers responsibility to + * recycle nativeData. * @param iBinder C++ pointer to IBinder. Does not take ownership of referenced object. */ private static BinderProxy getInstance(long nativeData, long iBinder) { - BinderProxy result = sProxyMap.get(iBinder); - if (result == null) { + BinderProxy result; + try { + result = sProxyMap.get(iBinder); + if (result != null) { + return result; + } result = new BinderProxy(nativeData); - sProxyMap.set(iBinder, result); + } catch (Throwable e) { + // We're throwing an exception (probably OOME); don't drop nativeData. + NativeAllocationRegistry.applyFreeFunction(NoImagePreloadHolder.sNativeFinalizer, + nativeData); + throw e; } + NoImagePreloadHolder.sRegistry.registerNativeAllocation(result, nativeData); + // The registry now owns nativeData, even if registration threw an exception. + sProxyMap.set(iBinder, result); return result; } private BinderProxy(long nativeData) { mNativeData = nativeData; - NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeData); } /** @@ -1057,8 +1068,9 @@ final class BinderProxy implements IBinder { // Use a Holder to allow static initialization of BinderProxy in the boot image, and // to avoid some initialization ordering issues. private static class NoImagePreloadHolder { + public static final long sNativeFinalizer = getNativeFinalizer(); public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( - BinderProxy.class.getClassLoader(), getNativeFinalizer(), NATIVE_ALLOCATION_SIZE); + BinderProxy.class.getClassLoader(), sNativeFinalizer, NATIVE_ALLOCATION_SIZE); } public native boolean pingBinder(); diff --git a/core/java/android/os/SimpleClock.java b/core/java/android/os/SimpleClock.java new file mode 100644 index 000000000000..efc271f5408f --- /dev/null +++ b/core/java/android/os/SimpleClock.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; + +/** {@hide} */ +public abstract class SimpleClock extends Clock { + private final ZoneId zone; + + public SimpleClock(ZoneId zone) { + this.zone = zone; + } + + @Override + public ZoneId getZone() { + return zone; + } + + @Override + public Clock withZone(ZoneId zone) { + return new SimpleClock(zone) { + @Override + public long millis() { + return SimpleClock.this.millis(); + } + }; + } + + @Override + public abstract long millis(); + + @Override + public Instant instant() { + return Instant.ofEpochMilli(millis()); + } +} diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java index c52c22d60ade..0f70427e6dc0 100644 --- a/core/java/android/os/SystemClock.java +++ b/core/java/android/os/SystemClock.java @@ -24,8 +24,7 @@ import android.util.Slog; import dalvik.annotation.optimization.CriticalNative; import java.time.Clock; -import java.time.Instant; -import java.time.ZoneId; +import java.time.DateTimeException; import java.time.ZoneOffset; /** @@ -148,8 +147,8 @@ public final class SystemClock { * @return if the clock was successfully set to the specified time. */ public static boolean setCurrentTimeMillis(long millis) { - IBinder b = ServiceManager.getService(Context.ALARM_SERVICE); - IAlarmManager mgr = IAlarmManager.Stub.asInterface(b); + final IAlarmManager mgr = IAlarmManager.Stub + .asInterface(ServiceManager.getService(Context.ALARM_SERVICE)); if (mgr == null) { return false; } @@ -174,27 +173,25 @@ public final class SystemClock { native public static long uptimeMillis(); /** + * @removed + */ + @Deprecated + public static @NonNull Clock uptimeMillisClock() { + return uptimeClock(); + } + + /** * Return {@link Clock} that starts at system boot, not counting time spent * in deep sleep. + * + * @removed */ - public static @NonNull Clock uptimeMillisClock() { - return new Clock() { - @Override - public ZoneId getZone() { - return ZoneOffset.UTC; - } - @Override - public Clock withZone(ZoneId zone) { - throw new UnsupportedOperationException(); - } + public static @NonNull Clock uptimeClock() { + return new SimpleClock(ZoneOffset.UTC) { @Override public long millis() { return SystemClock.uptimeMillis(); } - @Override - public Instant instant() { - return Instant.ofEpochMilli(millis()); - } }; } @@ -209,25 +206,15 @@ public final class SystemClock { /** * Return {@link Clock} that starts at system boot, including time spent in * sleep. + * + * @removed */ public static @NonNull Clock elapsedRealtimeClock() { - return new Clock() { - @Override - public ZoneId getZone() { - return ZoneOffset.UTC; - } - @Override - public Clock withZone(ZoneId zone) { - throw new UnsupportedOperationException(); - } + return new SimpleClock(ZoneOffset.UTC) { @Override public long millis() { return SystemClock.elapsedRealtime(); } - @Override - public Instant instant() { - return Instant.ofEpochMilli(millis()); - } }; } @@ -266,4 +253,62 @@ public final class SystemClock { */ @CriticalNative public static native long currentTimeMicro(); + + /** + * Returns milliseconds since January 1, 1970 00:00:00.0 UTC, synchronized + * using a remote network source outside the device. + * <p> + * While the time returned by {@link System#currentTimeMillis()} can be + * adjusted by the user, the time returned by this method cannot be adjusted + * by the user. Note that synchronization may occur using an insecure + * network protocol, so the returned time should not be used for security + * purposes. + * <p> + * This performs no blocking network operations and returns values based on + * a recent successful synchronization event; it will either return a valid + * time or throw. + * + * @throws DateTimeException when no accurate network time can be provided. + */ + public static long currentNetworkTimeMillis() { + final IAlarmManager mgr = IAlarmManager.Stub + .asInterface(ServiceManager.getService(Context.ALARM_SERVICE)); + if (mgr != null) { + try { + return mgr.currentNetworkTimeMillis(); + } catch (ParcelableException e) { + e.maybeRethrow(DateTimeException.class); + throw new RuntimeException(e); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } else { + throw new RuntimeException(new DeadSystemException()); + } + } + + /** + * Returns a {@link Clock} that starts at January 1, 1970 00:00:00.0 UTC, + * synchronized using a remote network source outside the device. + * <p> + * While the time returned by {@link System#currentTimeMillis()} can be + * adjusted by the user, the time returned by this method cannot be adjusted + * by the user. Note that synchronization may occur using an insecure + * network protocol, so the returned time should not be used for security + * purposes. + * <p> + * This performs no blocking network operations and returns values based on + * a recent successful synchronization event; it will either return a valid + * time or throw. + * + * @throws DateTimeException when no accurate network time can be provided. + */ + public static @NonNull Clock currentNetworkTimeClock() { + return new SimpleClock(ZoneOffset.UTC) { + @Override + public long millis() { + return SystemClock.currentNetworkTimeMillis(); + } + }; + } } diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java index 51b77980fcf4..e436bc6ea30f 100644 --- a/core/java/android/print/PrintManager.java +++ b/core/java/android/print/PrintManager.java @@ -18,6 +18,7 @@ package android.print; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; @@ -27,6 +28,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.IntentSender; import android.content.IntentSender.SendIntentException; +import android.content.pm.PackageManager; import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.CancellationSignal; @@ -104,6 +106,7 @@ import java.util.Map; * @see PrintJobInfo */ @SystemService(Context.PRINT_SERVICE) +@RequiresFeature(PackageManager.FEATURE_PRINTING) public final class PrintManager { private static final String LOG_TAG = "PrintManager"; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 598eeefbd81a..26c3732f29a5 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8760,6 +8760,7 @@ public final class Settings { /** {@hide} */ public static final String NETSTATS_POLL_INTERVAL = "netstats_poll_interval"; /** {@hide} */ + @Deprecated public static final String NETSTATS_TIME_CACHE_MAX_AGE = "netstats_time_cache_max_age"; /** {@hide} */ public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes"; @@ -10478,6 +10479,7 @@ public final class Settings { * track_cpu_times_by_proc_state (boolean) * track_cpu_active_cluster_time (boolean) * read_binary_cpu_time (boolean) + * proc_state_cpu_times_read_delay_ms (long) * </pre> * * <p> diff --git a/core/java/android/provider/SettingsSlicesContract.java b/core/java/android/provider/SettingsSlicesContract.java index f79d852ddefc..7dc948899dfe 100644 --- a/core/java/android/provider/SettingsSlicesContract.java +++ b/core/java/android/provider/SettingsSlicesContract.java @@ -31,12 +31,12 @@ import android.net.Uri; * <p> * {@link Uri} builder example: * <pre> - * Uri wifiActionUri = AUTHORITY_URI + * Uri wifiActionUri = BASE_URI * .buildUpon() * .appendPath(PATH_SETTING_ACTION) * .appendPath(KEY_WIFI) * .build(); - * Uri bluetoothIntentUri = AUTHORITY_URI + * Uri bluetoothIntentUri = BASE_URI * .buildUpon() * .appendPath(PATH_SETTING_INTENT) * .appendPath(KEY_BLUETOOTH) diff --git a/core/java/android/text/style/TypefaceSpan.java b/core/java/android/text/style/TypefaceSpan.java index 162281250208..908de2988be9 100644 --- a/core/java/android/text/style/TypefaceSpan.java +++ b/core/java/android/text/style/TypefaceSpan.java @@ -17,6 +17,8 @@ package android.text.style; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.graphics.LeakyTypefaceStorage; import android.graphics.Paint; import android.graphics.Typeface; import android.os.Parcel; @@ -25,33 +27,69 @@ import android.text.TextPaint; import android.text.TextUtils; /** - * Changes the typeface family of the text to which the span is attached. Examples of typeface - * family include "monospace", "serif", and "sans-serif". + * Span that updates the typeface of the text it's attached to. The <code>TypefaceSpan</code> can + * be constructed either based on a font family or based on a <code>Typeface</code>. When + * {@link #TypefaceSpan(String)} is used, the previous style of the <code>TextView</code> is kept. + * When {@link #TypefaceSpan(Typeface)} is used, the <code>Typeface</code> style replaces the + * <code>TextView</code>'s style. * <p> - * For example, change the typeface of a text to "monospace" like this: + * For example, let's consider a <code>TextView</code> with + * <code>android:textStyle="italic"</code> and a typeface created based on a font from resources, + * with a bold style. When applying a <code>TypefaceSpan</code> based the typeface, the text will + * only keep the bold style, overriding the <code>TextView</code>'s textStyle. When applying a + * <code>TypefaceSpan</code> based on a font family: "monospace", the resulted text will keep the + * italic style. * <pre> - * SpannableString string = new SpannableString("Text with typeface span"); - * string.setSpan(new TypefaceSpan("monospace"), 10, 18, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + * Typeface myTypeface = Typeface.create(ResourcesCompat.getFont(context, R.font.acme), + * Typeface.BOLD); + * SpannableString string = new SpannableString("Text with typeface span."); + * string.setSpan(new TypefaceSpan(myTypeface), 10, 18, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + * string.setSpan(new TypefaceSpan("monospace"), 19, 22, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); * </pre> * <img src="{@docRoot}reference/android/images/text/style/typefacespan.png" /> - * <figcaption>Text with "monospace" typeface family.</figcaption> + * <figcaption>Text with <code>TypefaceSpan</code>s constructed based on a font from resource and + * from a font family.</figcaption> */ public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan { + @Nullable private final String mFamily; + @Nullable + private final Typeface mTypeface; + /** - * Constructs a {@link TypefaceSpan} based on a font family. + * Constructs a {@link TypefaceSpan} based on the font family. The previous style of the + * TextPaint is kept. If the font family is null, the text paint is not modified. * - * @param family The font family for this typeface. Examples include - * "monospace", "serif", and "sans-serif". + * @param family The font family for this typeface. Examples include + * "monospace", "serif", and "sans-serif" */ - public TypefaceSpan(String family) { - mFamily = family; + public TypefaceSpan(@Nullable String family) { + this(family, null); } + /** + * Constructs a {@link TypefaceSpan} from a {@link Typeface}. The previous style of the + * TextPaint is overridden and the style of the typeface is used. + * + * @param typeface the typeface + */ + public TypefaceSpan(@NonNull Typeface typeface) { + this(null, typeface); + } + + /** + * Constructs a {@link TypefaceSpan} from a parcel. + */ public TypefaceSpan(@NonNull Parcel src) { mFamily = src.readString(); + mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src); + } + + private TypefaceSpan(@Nullable String family, @Nullable Typeface typeface) { + mFamily = family; + mTypeface = typeface; } @Override @@ -79,37 +117,59 @@ public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan @Override public void writeToParcelInternal(@NonNull Parcel dest, int flags) { dest.writeString(mFamily); + LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest); } /** - * Returns the font family name. + * Returns the font family name set in the span. + * + * @return the font family name + * @see #TypefaceSpan(String) */ + @Nullable public String getFamily() { return mFamily; } + /** + * Returns the typeface set in the span. + * + * @return the typeface set + * @see #TypefaceSpan(Typeface) + */ + @Nullable + public Typeface getTypeface() { + return mTypeface; + } + @Override - public void updateDrawState(@NonNull TextPaint textPaint) { - apply(textPaint, mFamily); + public void updateDrawState(@NonNull TextPaint ds) { + updateTypeface(ds); } @Override - public void updateMeasureState(@NonNull TextPaint textPaint) { - apply(textPaint, mFamily); + public void updateMeasureState(@NonNull TextPaint paint) { + updateTypeface(paint); } - private static void apply(@NonNull Paint paint, String family) { - int oldStyle; + private void updateTypeface(@NonNull Paint paint) { + if (mTypeface != null) { + paint.setTypeface(mTypeface); + } else if (mFamily != null) { + applyFontFamily(paint, mFamily); + } + } + private void applyFontFamily(@NonNull Paint paint, @NonNull String family) { + int style; Typeface old = paint.getTypeface(); if (old == null) { - oldStyle = 0; + style = Typeface.NORMAL; } else { - oldStyle = old.getStyle(); + style = old.getStyle(); } - - Typeface tf = Typeface.create(family, oldStyle); - int fake = oldStyle & ~tf.getStyle(); + final Typeface styledTypeface = Typeface.create(family, style); + int fake = style & ~styledTypeface.getStyle(); if ((fake & Typeface.BOLD) != 0) { paint.setFakeBoldText(true); @@ -118,7 +178,6 @@ public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan if ((fake & Typeface.ITALIC) != 0) { paint.setTextSkewX(-0.25f); } - - paint.setTypeface(tf); + paint.setTypeface(styledTypeface); } } diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java index a61c8c1dba68..0b72c22d4e27 100644 --- a/core/java/android/view/DisplayCutout.java +++ b/core/java/android/view/DisplayCutout.java @@ -52,6 +52,16 @@ public final class DisplayCutout { private static final String TAG = "DisplayCutout"; private static final String DP_MARKER = "@dp"; + /** + * Category for overlays that allow emulating a display cutout on devices that don't have + * one. + * + * @see android.content.om.IOverlayManager + * @hide + */ + public static final String EMULATION_OVERLAY_CATEGORY = + "com.android.internal.display_cutout_emulation"; + private static final Rect ZERO_RECT = new Rect(); private static final Region EMPTY_REGION = new Region(); diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 134dc1f060c6..7792fa640015 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -24,6 +24,7 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.SystemService; import android.content.ComponentName; import android.content.Context; @@ -135,6 +136,7 @@ import sun.misc.Cleaner; * <p>It is safe to call into its methods from any thread. */ @SystemService(Context.AUTOFILL_MANAGER_SERVICE) +@RequiresFeature(PackageManager.FEATURE_AUTOFILL) public final class AutofillManager { private static final String TAG = "AutofillManager"; diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 9de26a86f20f..a2280a4acd11 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -20,10 +20,12 @@ import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; +import android.content.pm.PackageManager; import android.graphics.Rect; import android.inputmethodservice.InputMethodService; import android.net.Uri; @@ -213,6 +215,7 @@ import java.util.concurrent.TimeUnit; * </ul> */ @SystemService(Context.INPUT_METHOD_SERVICE) +@RequiresFeature(PackageManager.FEATURE_INPUT_METHODS) public final class InputMethodManager { static final boolean DEBUG = false; static final String TAG = "InputMethodManager"; diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index 7ea1f1edadf5..d32e93c7a862 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -917,7 +917,7 @@ public class LinearLayout extends ViewGroup { // measurement on any children, we need to measure them now. int remainingExcess = heightSize - mTotalLength + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace); - if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) { + if (skippedMeasure || totalWeight > 0.0f) { float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; mTotalLength = 0; @@ -1300,7 +1300,7 @@ public class LinearLayout extends ViewGroup { // measurement on any children, we need to measure them now. int remainingExcess = widthSize - mTotalLength + (mAllowInconsistentMeasurement ? 0 : usedExcessSpace); - if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) { + if (skippedMeasure || totalWeight > 0.0f) { float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1; diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 4c5991ef8afb..4e515918a0cd 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -230,6 +230,13 @@ public class BatteryStatsImpl extends BatteryStats { @VisibleForTesting protected final SparseIntArray mPendingUids = new SparseIntArray(); + @GuardedBy("this") + private long mNumCpuTimeReads; + @GuardedBy("this") + private long mNumBatchedCpuTimeReads; + @GuardedBy("this") + private long mCpuTimeReadsTrackingStartTime = SystemClock.uptimeMillis(); + /** Container for Resource Power Manager stats. Updated by updateRpmStatsLocked. */ private final RpmStats mTmpRpmStats = new RpmStats(); /** The soonest the RPM stats can be updated after it was last updated. */ @@ -485,7 +492,8 @@ public class BatteryStatsImpl extends BatteryStats { Future<?> scheduleSync(String reason, int flags); Future<?> scheduleCpuSyncDueToRemovedUid(int uid); - Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff); + Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff, + long delayMillis); Future<?> scheduleCopyFromAllUidsCpuTimes(boolean onBattery, boolean onBatteryScreenOff); Future<?> scheduleCpuSyncDueToSettingChange(); Future<?> scheduleCpuSyncDueToScreenStateChange(boolean onBattery, @@ -9694,7 +9702,11 @@ public class BatteryStatsImpl extends BatteryStats { if (mBsi.mPendingUids.size() == 0) { mBsi.mExternalSync.scheduleReadProcStateCpuTimes( mBsi.mOnBatteryTimeBase.isRunning(), - mBsi.mOnBatteryScreenOffTimeBase.isRunning()); + mBsi.mOnBatteryScreenOffTimeBase.isRunning(), + mBsi.mConstants.PROC_STATE_CPU_TIMES_READ_DELAY_MS); + mBsi.mNumCpuTimeReads++; + } else { + mBsi.mNumBatchedCpuTimeReads++; } if (mBsi.mPendingUids.indexOfKey(mUid) < 0 || ArrayUtils.contains(CRITICAL_PROC_STATES, mProcessState)) { @@ -11228,6 +11240,25 @@ public class BatteryStatsImpl extends BatteryStats { private ModemActivityInfo mLastModemActivityInfo = new ModemActivityInfo(0, 0, 0, new int[0], 0, 0); + private ModemActivityInfo getDeltaModemActivityInfo(ModemActivityInfo activityInfo) { + if (activityInfo == null) { + return null; + } + int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS]; + for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) { + txTimeMs[i] = activityInfo.getTxTimeMillis()[i] + - mLastModemActivityInfo.getTxTimeMillis()[i]; + } + ModemActivityInfo deltaInfo = new ModemActivityInfo(activityInfo.getTimestamp(), + activityInfo.getSleepTimeMillis() - mLastModemActivityInfo.getSleepTimeMillis(), + activityInfo.getIdleTimeMillis() - mLastModemActivityInfo.getIdleTimeMillis(), + txTimeMs, + activityInfo.getRxTimeMillis() - mLastModemActivityInfo.getRxTimeMillis(), + activityInfo.getEnergyUsed() - mLastModemActivityInfo.getEnergyUsed()); + mLastModemActivityInfo = activityInfo; + return deltaInfo; + } + /** * Distribute Cell radio energy info and network traffic to apps. */ @@ -11235,9 +11266,10 @@ public class BatteryStatsImpl extends BatteryStats { if (DEBUG_ENERGY) { Slog.d(TAG, "Updating mobile radio stats with " + activityInfo); } + ModemActivityInfo deltaInfo = getDeltaModemActivityInfo(activityInfo); // Add modem tx power to history. - addModemTxPowerToHistory(activityInfo); + addModemTxPowerToHistory(deltaInfo); // Grab a separate lock to acquire the network stats, which may do I/O. NetworkStats delta = null; @@ -11251,22 +11283,6 @@ public class BatteryStatsImpl extends BatteryStats { } } - int rxTimeMs = 0; - int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS]; - int idleTimeMs = 0; - int sleepTimeMs = 0; - if (activityInfo != null) { - rxTimeMs = activityInfo.getRxTimeMillis() - mLastModemActivityInfo.getRxTimeMillis(); - for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) { - txTimeMs[i] = activityInfo.getTxTimeMillis()[i] - - mLastModemActivityInfo.getTxTimeMillis()[i]; - } - idleTimeMs = - activityInfo.getIdleTimeMillis() - mLastModemActivityInfo.getIdleTimeMillis(); - sleepTimeMs = - activityInfo.getSleepTimeMillis() - mLastModemActivityInfo.getSleepTimeMillis(); - } - synchronized (this) { if (!mOnBatteryInternal) { if (delta != null) { @@ -11275,14 +11291,14 @@ public class BatteryStatsImpl extends BatteryStats { return; } - if (activityInfo != null) { + if (deltaInfo != null) { mHasModemReporting = true; mModemActivity.getIdleTimeCounter().addCountLocked( - idleTimeMs); - mModemActivity.getRxTimeCounter().addCountLocked(rxTimeMs); + deltaInfo.getIdleTimeMillis()); + mModemActivity.getRxTimeCounter().addCountLocked(deltaInfo.getRxTimeMillis()); for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) { mModemActivity.getTxTimeCounters()[lvl] - .addCountLocked(txTimeMs[lvl]); + .addCountLocked(deltaInfo.getTxTimeMillis()[lvl]); } // POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V. @@ -11290,16 +11306,17 @@ public class BatteryStatsImpl extends BatteryStats { PowerProfile.POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE) / 1000.0; if (opVolt != 0) { double energyUsed = - sleepTimeMs * + deltaInfo.getSleepTimeMillis() * mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_SLEEP) - + idleTimeMs * + + deltaInfo.getIdleTimeMillis() * mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE) - + rxTimeMs * + + deltaInfo.getRxTimeMillis() * mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX); + int[] txTimeMs = deltaInfo.getTxTimeMillis(); for (int i = 0; i < Math.min(txTimeMs.length, - SignalStrength.NUM_SIGNAL_STRENGTH_BINS); i++) { + SignalStrength.NUM_SIGNAL_STRENGTH_BINS); i++) { energyUsed += txTimeMs[i] * mPowerProfile.getAveragePower( - PowerProfile.POWER_MODEM_CONTROLLER_TX, i); + PowerProfile.POWER_MODEM_CONTROLLER_TX, i); } // We store the power drain as mAms. @@ -11375,11 +11392,11 @@ public class BatteryStatsImpl extends BatteryStats { radioTime -= appRadioTime; totalPackets -= appPackets; - if (activityInfo != null) { + if (deltaInfo != null) { ControllerActivityCounterImpl activityCounter = u.getOrCreateModemControllerActivityLocked(); if (totalRxPackets > 0 && entry.rxPackets > 0) { - final long rxMs = (entry.rxPackets * rxTimeMs) + final long rxMs = (entry.rxPackets * deltaInfo.getRxTimeMillis()) / totalRxPackets; activityCounter.getRxTimeCounter().addCountLocked(rxMs); } @@ -11387,7 +11404,7 @@ public class BatteryStatsImpl extends BatteryStats { if (totalTxPackets > 0 && entry.txPackets > 0) { for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) { long txMs = - entry.txPackets * txTimeMs[lvl]; + entry.txPackets * deltaInfo.getTxTimeMillis()[lvl]; txMs /= totalTxPackets; activityCounter.getTxTimeCounters()[lvl].addCountLocked(txMs); } @@ -13167,15 +13184,19 @@ public class BatteryStatsImpl extends BatteryStats { = "track_cpu_active_cluster_time"; public static final String KEY_READ_BINARY_CPU_TIME = "read_binary_cpu_time"; + public static final String KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS + = "proc_state_cpu_times_read_delay_ms"; private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true; private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true; private static final boolean DEFAULT_READ_BINARY_CPU_TIME = false; + private static final long DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS = 5_000; public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE; public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME; // Not used right now. public boolean READ_BINARY_CPU_TIME = DEFAULT_READ_BINARY_CPU_TIME; + public long PROC_STATE_CPU_TIMES_READ_DELAY_MS = DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -13215,7 +13236,9 @@ public class BatteryStatsImpl extends BatteryStats { KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME, DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME); READ_BINARY_CPU_TIME = mParser.getBoolean( KEY_READ_BINARY_CPU_TIME, DEFAULT_READ_BINARY_CPU_TIME); - + updateProcStateCpuTimesReadDelayMs(PROC_STATE_CPU_TIMES_READ_DELAY_MS, + mParser.getLong(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS, + DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS)); } } @@ -13224,6 +13247,19 @@ public class BatteryStatsImpl extends BatteryStats { if (isEnabled && !wasEnabled) { mKernelSingleUidTimeReader.markDataAsStale(true); mExternalSync.scheduleCpuSyncDueToSettingChange(); + + mNumCpuTimeReads = 0; + mNumBatchedCpuTimeReads = 0; + mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis(); + } + } + + private void updateProcStateCpuTimesReadDelayMs(long oldDelayMillis, long newDelayMillis) { + PROC_STATE_CPU_TIMES_READ_DELAY_MS = newDelayMillis; + if (oldDelayMillis != newDelayMillis) { + mNumCpuTimeReads = 0; + mNumBatchedCpuTimeReads = 0; + mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis(); } } @@ -13234,6 +13270,8 @@ public class BatteryStatsImpl extends BatteryStats { pw.println(TRACK_CPU_ACTIVE_CLUSTER_TIME); pw.print(KEY_READ_BINARY_CPU_TIME); pw.print("="); pw.println(READ_BINARY_CPU_TIME); + pw.print(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS); pw.print("="); + pw.println(PROC_STATE_CPU_TIMES_READ_DELAY_MS); } } @@ -14943,5 +14981,11 @@ public class BatteryStatsImpl extends BatteryStats { mCameraOnTimer.logState(pr, " "); } super.dumpLocked(context, pw, flags, reqUid, histStart); + pw.print("Total cpu time reads: "); + pw.println(mNumCpuTimeReads); + pw.print("Batched cpu time reads: "); + pw.println(mNumBatchedCpuTimeReads); + pw.print("Batching Duration (min): "); + pw.println((mClocks.uptimeMillis() - mCpuTimeReadsTrackingStartTime) / (60 * 1000)); } } diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 5b788a644852..d17993a72aaf 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -663,7 +663,8 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get()); if (env->ExceptionCheck()) { - gNativeDataCache = nativeData; + // In the exception case, getInstance still took ownership of nativeData. + gNativeDataCache = nullptr; return NULL; } BinderProxyNativeData* actualNativeData = getBPNativeData(env, object); diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 287f29615e2b..32fe2b2a72d8 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2558,6 +2558,9 @@ <!-- Package name of base package whose resources will be overlaid. --> <attr name="targetPackage" /> + <!-- Category of the resource overlay. --> + <attr name="category" format="string"/> + <!-- Load order of overlay package. --> <attr name="priority" /> diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml index e80f16c466b3..6e8134b079b2 100644 --- a/core/res/res/values/colors_material.xml +++ b/core/res/res/values/colors_material.xml @@ -78,9 +78,9 @@ <item name="secondary_content_alpha_material_dark" format="float" type="dimen">.7</item> <item name="secondary_content_alpha_material_light" format="float" type="dimen">0.54</item> - <item name="highlight_alpha_material_light" format="float" type="dimen">0.16</item> - <item name="highlight_alpha_material_dark" format="float" type="dimen">0.16</item> - <item name="highlight_alpha_material_colored" format="float" type="dimen">0.16</item> + <item name="highlight_alpha_material_light" format="float" type="dimen">0.10</item> + <item name="highlight_alpha_material_dark" format="float" type="dimen">0.10</item> + <item name="highlight_alpha_material_colored" format="float" type="dimen">0.10</item> <!-- Primary & accent colors --> <eat-comment /> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index f6a11bd0352a..eed0e463df99 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -41,58 +41,44 @@ please see themes_device_defaults.xml. #Theme_Holo} or {@link #Theme_DeviceDefault}.</p> --> <style name="Theme"> - <item name="isLightTheme">false</item> + <item name="colorForeground">@color/bright_foreground_dark</item> <item name="colorForegroundInverse">@color/bright_foreground_dark_inverse</item> <item name="colorBackground">@color/background_dark</item> <item name="colorBackgroundFloating">?attr/colorBackground</item> <item name="colorBackgroundCacheHint">?attr/colorBackground</item> - - <item name="colorPressedHighlight">@color/legacy_pressed_highlight</item> - <item name="colorLongPressedHighlight">@color/legacy_long_pressed_highlight</item> - <item name="colorFocusedHighlight">@color/legacy_selected_highlight</item> - <item name="colorMultiSelectHighlight">@color/legacy_selected_highlight</item> - <item name="colorActivatedHighlight">@color/legacy_selected_highlight</item> - - <item name="colorPrimaryDark">@color/legacy_primary_dark</item> - <item name="colorPrimary">@color/legacy_primary</item> - <item name="colorSecondary">?attr/colorPrimary</item> - <item name="colorControlActivated">@color/legacy_control_activated</item> - <item name="colorControlNormal">@color/legacy_control_normal</item> - <item name="colorControlHighlight">@color/legacy_button_pressed</item> - <item name="colorButtonNormal">@color/legacy_button_normal</item> - <item name="colorEdgeEffect">?attr/colorPrimary</item> - <item name="colorError">@color/red</item> - <item name="disabledAlpha">0.5</item> + <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item> + <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_dark</item> <item name="backgroundDimAmount">0.6</item> + <item name="colorError">@color/red</item> <!-- Text styles --> <item name="textAppearance">@style/TextAppearance</item> <item name="textAppearanceInverse">@style/TextAppearance.Inverse</item> <item name="textColorPrimary">@color/primary_text_dark</item> - <item name="textColorSecondary">@color/secondary_text_dark</item> - <item name="textColorTertiary">@color/tertiary_text_dark</item> <item name="textColorPrimaryInverse">@color/primary_text_light</item> - <item name="textColorSecondaryInverse">@color/secondary_text_light</item> - <item name="textColorTertiaryInverse">@color/tertiary_text_light</item> <item name="textColorPrimaryActivated">@color/primary_text_dark</item> - <item name="textColorSecondaryActivated">@color/secondary_text_dark</item> <item name="textColorPrimaryDisableOnly">@color/primary_text_dark_disable_only</item> <item name="textColorPrimaryInverseDisableOnly">@color/primary_text_light_disable_only</item> + <item name="textColorPrimaryInverseNoDisable">@color/primary_text_light_nodisable</item> <item name="textColorPrimaryNoDisable">@color/primary_text_dark_nodisable</item> + <item name="textColorSecondary">@color/secondary_text_dark</item> + <item name="textColorSecondaryInverse">@color/secondary_text_light</item> + <item name="textColorSecondaryActivated">@color/secondary_text_dark</item> <item name="textColorSecondaryNoDisable">@color/secondary_text_dark_nodisable</item> - <item name="textColorPrimaryInverseNoDisable">@color/primary_text_light_nodisable</item> <item name="textColorSecondaryInverseNoDisable">@color/secondary_text_light_nodisable</item> + <item name="textColorTertiary">@color/tertiary_text_dark</item> + <item name="textColorTertiaryInverse">@color/tertiary_text_light</item> <item name="textColorHint">@color/hint_foreground_dark</item> <item name="textColorHintInverse">@color/hint_foreground_light</item> - <item name="textColorSearchUrl">@color/search_url_text</item> <item name="textColorHighlight">@color/highlighted_text_dark</item> <item name="textColorHighlightInverse">@color/highlighted_text_light</item> <item name="textColorLink">@color/link_text_dark</item> <item name="textColorLinkInverse">@color/link_text_light</item> + <item name="textColorSearchUrl">@color/search_url_text</item> <item name="textColorAlertDialogListItem">@color/primary_text_light_disable_only</item> <item name="textAppearanceLarge">@style/TextAppearance.Large</item> @@ -120,14 +106,19 @@ please see themes_device_defaults.xml. <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Widget.PopupMenu.Large</item> <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Widget.PopupMenu.Small</item> + <item name="textAppearancePopupMenuHeader">@null</item> <!-- Button styles --> <item name="buttonStyle">@style/Widget.Button</item> + <item name="buttonStyleSmall">@style/Widget.Button.Small</item> <item name="buttonStyleInset">@style/Widget.Button.Inset</item> + <item name="buttonStyleToggle">@style/Widget.Button.Toggle</item> + <item name="buttonCornerRadius">0dp</item> <item name="switchStyle">@style/Widget.CompoundButton.Switch</item> + <item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.MediaRouteButton</item> <item name="selectableItemBackground">@drawable/item_background</item> <item name="selectableItemBackgroundBorderless">?attr/selectableItemBackground</item> @@ -156,7 +147,6 @@ please see themes_device_defaults.xml. <item name="listChoiceIndicatorMultiple">@drawable/btn_check</item> <item name="listChoiceBackgroundIndicator">@drawable/list_selector_background</item> - <item name="activatedBackgroundIndicator">@drawable/activated_background</item> <item name="listDividerAlertDialog">@drawable/divider_horizontal_bright</item> @@ -215,6 +205,7 @@ please see themes_device_defaults.xml. <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title</item> <item name="dialogTitleDecorLayout">@layout/dialog_title</item> <item name="dialogPreferredPadding">@dimen/dialog_padding</item> + <item name="dialogCornerRadius">0dp</item> <!-- AlertDialog attributes --> <item name="alertDialogTheme">@style/Theme.Dialog.Alert</item> @@ -239,6 +230,7 @@ please see themes_device_defaults.xml. <item name="panelMenuIsCompact">false</item> <item name="panelMenuListWidth">296dip</item> + <item name="panelMenuListTheme">@null</item> <!-- Scrollbar attributes --> <item name="scrollbarFadeDuration">250</item> @@ -316,8 +308,9 @@ please see themes_device_defaults.xml. <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.QuickContactBadgeSmall.WindowLarge</item> <item name="listPopupWindowStyle">@style/Widget.ListPopupWindow</item> <item name="popupMenuStyle">@style/Widget.PopupMenu</item> + <item name="popupTheme">@null</item> + <item name="stackViewStyle">@null</item> <item name="activityChooserViewStyle">@style/Widget.ActivityChooserView</item> - <item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.MediaRouteButton</item> <item name="fragmentBreadCrumbsStyle">@style/Widget.FragmentBreadCrumbs</item> <item name="contextPopupMenuStyle">?attr/popupMenuStyle</item> @@ -432,6 +425,22 @@ please see themes_device_defaults.xml. <item name="fastScrollOverlayPosition">floating</item> <item name="fastScrollTextColor">@color/primary_text_dark</item> + + <item name="colorPressedHighlight">@color/legacy_pressed_highlight</item> + <item name="colorLongPressedHighlight">@color/legacy_long_pressed_highlight</item> + <item name="colorFocusedHighlight">@color/legacy_selected_highlight</item> + <item name="colorMultiSelectHighlight">@color/legacy_selected_highlight</item> + <item name="colorActivatedHighlight">@color/legacy_selected_highlight</item> + + <item name="colorPrimaryDark">@color/legacy_primary_dark</item> + <item name="colorPrimary">@color/legacy_primary</item> + <item name="colorSecondary">?attr/colorPrimary</item> + <item name="colorControlActivated">@color/legacy_control_activated</item> + <item name="colorControlNormal">@color/legacy_control_normal</item> + <item name="colorControlHighlight">@color/legacy_button_pressed</item> + <item name="colorButtonNormal">@color/legacy_button_normal</item> + <item name="colorEdgeEffect">?attr/colorPrimary</item> + <!-- Accessibility focused drawable --> <item name="accessibilityFocusedDrawable">@drawable/view_accessibility_focused</item> diff --git a/core/res/res/values/themes_holo.xml b/core/res/res/values/themes_holo.xml index 8f73479e95ac..3fe7c05c16e2 100644 --- a/core/res/res/values/themes_holo.xml +++ b/core/res/res/values/themes_holo.xml @@ -29,20 +29,9 @@ please see themes_device_defaults.xml. =============================================================== --> <resources> - <!-- The default theme for apps on API level 10 and lower. This is the theme used for - activities that have not explicitly set their own theme. - <p>You can count on this being a dark - background with light text on top, but should try to make no - other assumptions about its appearance. In particular, the text - inside of widgets using this theme may be completely different, - with the widget container being a light color and the text on top - of it a dark color. - <p>If you're developing for API level 11 and higher, you should instead use {@link - #Theme_Holo} or {@link #Theme_DeviceDefault}.</p> - --> <!-- Honeycomb holographic theme (dark version). - <p>This is the default system theme for apps that target API level 11 - 13. Starting + <p>This is the default system theme for apps that target API level 11 - 20. Starting with API level 14, the default system theme is supplied by {@link #Theme_DeviceDefault}, which might apply a different style on different devices. If you want to ensure that your app consistently uses the Holo theme at all times, you must explicitly declare it in your @@ -60,7 +49,9 @@ please see themes_device_defaults.xml. TextAppearance.Holo.Widget.PopupMenu.Large}). Specific resources used by Holo are named using the convention @type/foo_bar_baz_holo with trailing _dark or _light specifiers if they are not shared between both light and - dark versions of the theme. --> + dark versions of the theme. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo"> <item name="colorForeground">@color/bright_foreground_holo_dark</item> <item name="colorForegroundInverse">@color/bright_foreground_inverse_holo_dark</item> @@ -68,21 +59,10 @@ please see themes_device_defaults.xml. <item name="colorBackgroundFloating">@color/background_holo_dark</item> <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_holo_dark</item> <item name="disabledAlpha">0.5</item> + <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item> + <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_dark</item> <item name="backgroundDimAmount">0.6</item> - - <item name="colorPressedHighlight">@color/holo_gray_light</item> - <item name="colorLongPressedHighlight">@color/holo_gray_bright</item> - <item name="colorFocusedHighlight">@color/holo_blue_dark</item> - <item name="colorMultiSelectHighlight">@color/holo_green_light</item> - <item name="colorActivatedHighlight">@color/holo_blue_dark</item> - - <item name="colorPrimaryDark">@color/holo_primary_dark</item> - <item name="colorPrimary">@color/holo_primary</item> - <item name="colorControlActivated">@color/holo_control_activated</item> - <item name="colorControlNormal">@color/holo_control_normal</item> - <item name="colorControlHighlight">@color/holo_button_pressed</item> - <item name="colorButtonNormal">@color/holo_button_normal</item> - <item name="colorEdgeEffect">?attr/colorPrimary</item> + <item name="colorError">@color/error_color_material_dark</item> <!-- Text styles --> <item name="textAppearance">@style/TextAppearance.Holo</item> @@ -132,6 +112,7 @@ please see themes_device_defaults.xml. <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Holo.Widget.PopupMenu.Large</item> <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Holo.Widget.PopupMenu.Small</item> + <item name="textAppearancePopupMenuHeader">@null</item> <item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item</item> <item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container</item> @@ -144,6 +125,8 @@ please see themes_device_defaults.xml. <item name="buttonStyleInset">@style/Widget.Holo.Button.Inset</item> <item name="buttonStyleToggle">@style/Widget.Holo.Button.Toggle</item> + <item name="buttonCornerRadius">0dp</item> + <item name="switchStyle">@style/Widget.Holo.CompoundButton.Switch</item> <item name="mediaRouteButtonStyle">@style/Widget.Holo.MediaRouteButton</item> @@ -157,6 +140,7 @@ please see themes_device_defaults.xml. <item name="listPreferredItemHeightSmall">48dip</item> <item name="listPreferredItemHeightLarge">80dip</item> <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item> + <item name="textAppearanceListItem">?attr/textAppearanceLarge</item> <item name="textAppearanceListItemSmall">?attr/textAppearanceMedium</item> <item name="textAppearanceListItemSecondary">?attr/textAppearanceSmall</item> <item name="listPreferredItemPaddingLeft">8dip</item> @@ -212,6 +196,8 @@ please see themes_device_defaults.xml. <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_holo</item> <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_holo</item> <item name="dialogTitleDecorLayout">@layout/dialog_title_holo</item> + <item name="dialogPreferredPadding">@dimen/dialog_padding</item> + <item name="dialogCornerRadius">0dp</item> <!-- AlertDialog attributes --> <item name="alertDialogTheme">@style/Theme.Holo.Dialog.Alert</item> @@ -251,6 +237,9 @@ please see themes_device_defaults.xml. <item name="textSelectHandleRight">@drawable/text_select_handle_right_material</item> <item name="textSelectHandle">@drawable/text_select_handle_middle_material</item> <item name="textSelectHandleWindowStyle">@style/Widget.Holo.TextSelectHandle</item> + <item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item</item> + <item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container</item> + <item name="textEditSuggestionHighlightStyle">@style/TextAppearance.Holo.SuggestionHighlight</item> <item name="textCursorDrawable">@drawable/text_cursor_holo_dark</item> <!-- Widget styles --> @@ -268,6 +257,7 @@ please see themes_device_defaults.xml. <item name="gridViewStyle">@style/Widget.Holo.GridView</item> <item name="imageButtonStyle">@style/Widget.Holo.ImageButton</item> <item name="imageWellStyle">@style/Widget.Holo.ImageWell</item> + <item name="listMenuViewStyle">@null</item> <item name="listViewStyle">@style/Widget.Holo.ListView</item> <item name="listViewWhiteStyle">@style/Widget.Holo.ListView.White</item> <item name="popupWindowStyle">@style/Widget.Holo.PopupWindow</item> @@ -308,9 +298,11 @@ please see themes_device_defaults.xml. <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Holo.QuickContactBadgeSmall.WindowLarge</item> <item name="listPopupWindowStyle">@style/Widget.Holo.ListPopupWindow</item> <item name="popupMenuStyle">@style/Widget.Holo.PopupMenu</item> + <item name="popupTheme">@null</item> <item name="stackViewStyle">@style/Widget.Holo.StackView</item> <item name="activityChooserViewStyle">@style/Widget.Holo.ActivityChooserView</item> <item name="fragmentBreadCrumbsStyle">@style/Widget.Holo.FragmentBreadCrumbs</item> + <item name="contextPopupMenuStyle">?attr/popupMenuStyle</item> <!-- Preference styles --> <item name="preferenceScreenStyle">@style/Preference.Holo.PreferenceScreen</item> @@ -327,8 +319,16 @@ please see themes_device_defaults.xml. <item name="editTextPreferenceStyle">@style/Preference.Holo.DialogPreference.EditTextPreference</item> <item name="ringtonePreferenceStyle">@style/Preference.Holo.RingtonePreference</item> <item name="preferenceLayoutChild">@layout/preference_child_holo</item> + <item name="preferencePanelStyle">@null</item> + <item name="preferenceHeaderPanelStyle">@null</item> + <item name="preferenceListStyle">@null</item> + <item name="preferenceFragmentListStyle">@null</item> + <item name="preferenceFragmentPaddingSide">@null</item> <item name="detailsElementBackground">@drawable/panel_bg_holo_dark</item> + <!-- PreferenceFrameLayout attributes --> + <item name="preferenceFrameLayoutStyle">@style/Widget.Holo.PreferenceFrameLayout</item> + <!-- Search widget styles --> <item name="searchWidgetCorpusItemBackground">@color/search_widget_corpus_item_background</item> @@ -348,9 +348,13 @@ please see themes_device_defaults.xml. <item name="actionBarStyle">@style/Widget.Holo.ActionBar</item> <item name="actionBarSize">@dimen/action_bar_default_height</item> <item name="actionModePopupWindowStyle">@style/Widget.Holo.PopupWindow.ActionMode</item> + <item name="actionMenuTextAppearance">@null</item> + <item name="actionMenuTextColor">@null</item> <item name="actionBarWidgetTheme">@null</item> - <item name="actionBarPopupTheme">@null</item> + <item name="actionBarPopupTheme">?attr/popupTheme</item> <item name="actionBarTheme">@null</item> + <item name="actionBarDivider">?attr/dividerVertical</item> + <item name="actionBarItemBackground">@null</item> <item name="actionModeCutDrawable">@drawable/ic_menu_cut_holo_dark</item> <item name="actionModeCopyDrawable">@drawable/ic_menu_copy_holo_dark</item> @@ -360,6 +364,8 @@ please see themes_device_defaults.xml. <item name="actionModeFindDrawable">@drawable/ic_menu_find_holo_dark</item> <item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_holo_dark</item> + <item name="toolbarStyle">@null</item> + <item name="dividerVertical">?attr/listDivider</item> <item name="dividerHorizontal">?attr/listDivider</item> <item name="buttonBarStyle">@style/Holo.ButtonBar</item> @@ -397,13 +403,39 @@ please see themes_device_defaults.xml. <item name="fastScrollTrackDrawable">@drawable/fastscroll_track_holo_dark</item> <item name="fastScrollOverlayPosition">atThumb</item> + + <item name="colorPrimaryDark">@color/holo_primary_dark</item> + <item name="colorPrimary">@color/holo_primary</item> + <item name="colorAccent">@color/holo_blue_dark</item> + <item name="colorEdgeEffect">?attr/colorPrimary</item> + + <item name="colorControlNormal">@color/holo_control_normal</item> + <item name="colorControlActivated">@color/holo_control_activated</item> + + <item name="colorControlHighlight">@color/holo_button_pressed</item> + <item name="colorButtonNormal">@color/holo_button_normal</item> + <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item> + + <!-- Tooltip popup properties --> + <item name="tooltipForegroundColor">@null</item> + <item name="tooltipBackgroundColor">@null</item> + + <!-- Holo-only color attributes --> + <item name="colorPressedHighlight">@color/holo_gray_light</item> + <item name="colorLongPressedHighlight">@color/holo_gray_bright</item> + <item name="colorFocusedHighlight">@color/holo_blue_dark</item> + <item name="colorMultiSelectHighlight">@color/holo_green_light</item> + <item name="colorActivatedHighlight">@color/holo_blue_dark</item> + </style> <!-- Honeycomb holographic theme (light version). The widgets in the holographic theme are translucent on their brackground, so applications must ensure that any background they use with this theme is itself light; otherwise, it will be difficult to see the widgets. This - UI style also includes a full action bar by default. --> + UI style also includes a full action bar by default. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light" parent="Theme.Light"> <item name="colorForeground">@color/bright_foreground_holo_light</item> <item name="colorForegroundInverse">@color/bright_foreground_inverse_holo_light</item> @@ -411,46 +443,36 @@ please see themes_device_defaults.xml. <item name="colorBackgroundFloating">@color/background_holo_light</item> <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_holo_light</item> <item name="disabledAlpha">0.5</item> + <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item> + <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_dark</item> <item name="backgroundDimAmount">0.6</item> - - <item name="colorPressedHighlight">@color/holo_gray_light</item> - <item name="colorLongPressedHighlight">@color/holo_gray_bright</item> - <item name="colorFocusedHighlight">@color/holo_blue_dark</item> - <item name="colorMultiSelectHighlight">@color/holo_green_light</item> - <item name="colorActivatedHighlight">@color/holo_blue_dark</item> - - <item name="colorPrimaryDark">@color/holo_light_primary_dark</item> - <item name="colorPrimary">@color/holo_light_primary</item> - <item name="colorControlActivated">@color/holo_light_control_activated</item> - <item name="colorControlNormal">@color/holo_light_control_normal</item> - <item name="colorControlHighlight">@color/holo_light_button_pressed</item> - <item name="colorButtonNormal">@color/holo_light_button_normal</item> + <item name="colorError">@color/error_color_material_light</item> <!-- Text styles --> <item name="textAppearance">@style/TextAppearance.Holo.Light</item> <item name="textAppearanceInverse">@style/TextAppearance.Holo.Light.Inverse</item> <item name="textColorPrimary">@color/primary_text_holo_light</item> - <item name="textColorSecondary">@color/secondary_text_holo_light</item> - <item name="textColorTertiary">@color/tertiary_text_holo_light</item> <item name="textColorPrimaryInverse">@color/primary_text_holo_dark</item> - <item name="textColorSecondaryInverse">@color/secondary_text_holo_dark</item> - <item name="textColorTertiaryInverse">@color/tertiary_text_holo_dark</item> <item name="textColorPrimaryActivated">@color/primary_text_holo_light</item> - <item name="textColorSecondaryActivated">@color/secondary_text_holo_light</item> <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_holo_light</item> <item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_holo_dark</item> + <item name="textColorPrimaryInverseNoDisable">@color/primary_text_nodisable_holo_dark</item> <item name="textColorPrimaryNoDisable">@color/primary_text_nodisable_holo_light</item> + <item name="textColorSecondary">@color/secondary_text_holo_light</item> + <item name="textColorSecondaryInverse">@color/secondary_text_holo_dark</item> + <item name="textColorSecondaryActivated">@color/secondary_text_holo_light</item> <item name="textColorSecondaryNoDisable">@color/secondary_text_nodisable_holo_light</item> - <item name="textColorPrimaryInverseNoDisable">@color/primary_text_nodisable_holo_dark</item> <item name="textColorSecondaryInverseNoDisable">@color/secondary_text_nodisable_holo_dark</item> + <item name="textColorTertiary">@color/tertiary_text_holo_light</item> + <item name="textColorTertiaryInverse">@color/tertiary_text_holo_dark</item> <item name="textColorHint">@color/hint_foreground_holo_light</item> <item name="textColorHintInverse">@color/hint_foreground_holo_dark</item> - <item name="textColorSearchUrl">@color/search_url_text_holo</item> <item name="textColorHighlight">@color/highlighted_text_holo_light</item> <item name="textColorHighlightInverse">@color/highlighted_text_holo_dark</item> <item name="textColorLink">@color/holo_blue_light</item> <item name="textColorLinkInverse">@color/holo_blue_light</item> + <item name="textColorSearchUrl">@color/search_url_text_holo</item> <item name="textColorAlertDialogListItem">@color/primary_text_holo_light</item> <item name="textAppearanceLarge">@style/TextAppearance.Holo.Light.Large</item> @@ -466,9 +488,6 @@ please see themes_device_defaults.xml. <item name="editTextColor">?attr/textColorPrimary</item> <item name="editTextBackground">@drawable/edit_text_holo_light</item> - <item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item</item> - <item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container</item> - <item name="textEditSuggestionHighlightStyle">@style/TextAppearance.Holo.SuggestionHighlight</item> <item name="candidatesTextStyleSpans">@string/candidates_style</item> @@ -477,6 +496,7 @@ please see themes_device_defaults.xml. <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Holo.Light.Widget.PopupMenu.Large</item> <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Holo.Light.Widget.PopupMenu.Small</item> + <item name="textAppearancePopupMenuHeader">@null</item> <!-- Button styles --> <item name="buttonStyle">@style/Widget.Holo.Light.Button</item> @@ -485,6 +505,8 @@ please see themes_device_defaults.xml. <item name="buttonStyleInset">@style/Widget.Holo.Light.Button.Inset</item> <item name="buttonStyleToggle">@style/Widget.Holo.Light.Button.Toggle</item> + <item name="buttonCornerRadius">0dp</item> + <item name="switchStyle">@style/Widget.Holo.Light.CompoundButton.Switch</item> <item name="mediaRouteButtonStyle">@style/Widget.Holo.Light.MediaRouteButton</item> @@ -498,6 +520,7 @@ please see themes_device_defaults.xml. <item name="listPreferredItemHeightSmall">48dip</item> <item name="listPreferredItemHeightLarge">80dip</item> <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item> + <item name="textAppearanceListItem">?attr/textAppearanceLarge</item> <item name="textAppearanceListItemSmall">?attr/textAppearanceMedium</item> <item name="textAppearanceListItemSecondary">?attr/textAppearanceSmall</item> <item name="listPreferredItemPaddingLeft">8dip</item> @@ -514,9 +537,10 @@ please see themes_device_defaults.xml. <item name="listChoiceIndicatorMultiple">@drawable/btn_check_holo_light</item> <item name="listChoiceBackgroundIndicator">@drawable/list_selector_holo_light</item> - <item name="activatedBackgroundIndicator">@drawable/activated_background_holo_light</item> + <item name="listDividerAlertDialog">@drawable/list_divider_holo_light</item> + <item name="expandableListPreferredItemPaddingLeft">40dip</item> <item name="expandableListPreferredChildPaddingLeft">?attr/expandableListPreferredItemPaddingLeft</item> @@ -524,8 +548,6 @@ please see themes_device_defaults.xml. <item name="expandableListPreferredItemIndicatorRight">0dip</item> <item name="expandableListPreferredChildIndicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item> <item name="expandableListPreferredChildIndicatorRight">?attr/expandableListPreferredItemIndicatorRight</item> - - <item name="listDividerAlertDialog">@drawable/list_divider_holo_light</item> <item name="findOnPageNextDrawable">@drawable/ic_find_next_holo_light</item> <item name="findOnPagePreviousDrawable">@drawable/ic_find_previous_holo_light</item> @@ -553,6 +575,8 @@ please see themes_device_defaults.xml. <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_holo</item> <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_holo</item> <item name="dialogTitleDecorLayout">@layout/dialog_title_holo</item> + <item name="dialogPreferredPadding">@dimen/dialog_padding</item> + <item name="dialogCornerRadius">0dp</item> <!-- AlertDialog attributes --> <item name="alertDialogTheme">@style/Theme.Holo.Light.Dialog.Alert</item> @@ -592,6 +616,9 @@ please see themes_device_defaults.xml. <item name="textSelectHandleRight">@drawable/text_select_handle_right_material</item> <item name="textSelectHandle">@drawable/text_select_handle_middle_material</item> <item name="textSelectHandleWindowStyle">@style/Widget.Holo.TextSelectHandle</item> + <item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item</item> + <item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container</item> + <item name="textEditSuggestionHighlightStyle">@style/TextAppearance.Holo.SuggestionHighlight</item> <item name="textCursorDrawable">@drawable/text_cursor_holo_light</item> <!-- Widget styles --> @@ -609,6 +636,7 @@ please see themes_device_defaults.xml. <item name="gridViewStyle">@style/Widget.Holo.Light.GridView</item> <item name="imageButtonStyle">@style/Widget.Holo.Light.ImageButton</item> <item name="imageWellStyle">@style/Widget.Holo.Light.ImageWell</item> + <item name="listMenuViewStyle">@null</item> <item name="listViewStyle">@style/Widget.Holo.Light.ListView</item> <item name="listViewWhiteStyle">@style/Widget.Holo.Light.ListView.White</item> <item name="popupWindowStyle">@style/Widget.Holo.Light.PopupWindow</item> @@ -649,9 +677,11 @@ please see themes_device_defaults.xml. <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Holo.QuickContactBadgeSmall.WindowLarge</item> <item name="listPopupWindowStyle">@style/Widget.Holo.Light.ListPopupWindow</item> <item name="popupMenuStyle">@style/Widget.Holo.Light.PopupMenu</item> + <item name="popupTheme">@null</item> <item name="stackViewStyle">@style/Widget.Holo.StackView</item> <item name="activityChooserViewStyle">@style/Widget.Holo.Light.ActivityChooserView</item> <item name="fragmentBreadCrumbsStyle">@style/Widget.Holo.Light.FragmentBreadCrumbs</item> + <item name="contextPopupMenuStyle">@null</item> <!-- Preference styles --> <item name="preferenceScreenStyle">@style/Preference.Holo.PreferenceScreen</item> @@ -668,6 +698,11 @@ please see themes_device_defaults.xml. <item name="editTextPreferenceStyle">@style/Preference.Holo.DialogPreference.EditTextPreference</item> <item name="ringtonePreferenceStyle">@style/Preference.Holo.RingtonePreference</item> <item name="preferenceLayoutChild">@layout/preference_child_holo</item> + <item name="preferencePanelStyle">@null</item> + <item name="preferenceHeaderPanelStyle">@null</item> + <item name="preferenceListStyle">@null</item> + <item name="preferenceFragmentListStyle">@null</item> + <item name="preferenceFragmentPaddingSide">@null</item> <item name="detailsElementBackground">@drawable/panel_bg_holo_light</item> <!-- PreferenceFrameLayout attributes --> @@ -680,6 +715,7 @@ please see themes_device_defaults.xml. <item name="actionDropDownStyle">@style/Widget.Holo.Light.Spinner.DropDown.ActionBar</item> <item name="actionButtonStyle">@style/Widget.Holo.Light.ActionButton</item> <item name="actionOverflowButtonStyle">@style/Widget.Holo.Light.ActionButton.Overflow</item> + <item name="actionOverflowMenuStyle">?attr/popupMenuStyle</item> <item name="actionModeBackground">@drawable/cab_background_top_holo_light</item> <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item> <item name="actionModeCloseDrawable">@drawable/ic_cab_done_holo_light</item> @@ -691,8 +727,12 @@ please see themes_device_defaults.xml. <item name="actionBarStyle">@style/Widget.Holo.Light.ActionBar.Solid</item> <item name="actionBarSize">@dimen/action_bar_default_height</item> <item name="actionModePopupWindowStyle">@style/Widget.Holo.Light.PopupWindow.ActionMode</item> + <item name="actionMenuTextAppearance">@null</item> + <item name="actionMenuTextColor">@null</item> <item name="actionBarWidgetTheme">@null</item> + <item name="actionBarPopupTheme">?attr/popupTheme</item> <item name="actionBarTheme">@null</item> + <item name="actionBarItemBackground">@null</item> <item name="actionModeCutDrawable">@drawable/ic_menu_cut_holo_light</item> <item name="actionModeCopyDrawable">@drawable/ic_menu_copy_holo_light</item> @@ -702,6 +742,8 @@ please see themes_device_defaults.xml. <item name="actionModeFindDrawable">@drawable/ic_menu_find_holo_light</item> <item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_holo_light</item> + <item name="toolbarStyle">@null</item> + <item name="dividerVertical">?attr/listDivider</item> <item name="dividerHorizontal">?attr/listDivider</item> <item name="buttonBarStyle">@style/Holo.Light.ButtonBar</item> @@ -736,11 +778,37 @@ please see themes_device_defaults.xml. <item name="fastScrollTrackDrawable">@drawable/fastscroll_track_holo_light</item> <item name="fastScrollOverlayPosition">atThumb</item> + <!-- Color palette --> + <item name="colorPrimaryDark">@color/holo_light_primary_dark</item> + <item name="colorPrimary">@color/holo_light_primary</item> + <item name="colorAccent">@color/holo_blue_light</item> + <item name="colorEdgeEffect">?attr/colorPrimary</item> + + <item name="colorControlNormal">@color/holo_light_control_normal</item> + <item name="colorControlActivated">@color/holo_light_control_activated</item> + + <item name="colorControlHighlight">@color/holo_light_button_pressed</item> + <item name="colorButtonNormal">@color/holo_light_button_normal</item> + <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item> + + <!-- Tooltip popup properties --> + <item name="tooltipForegroundColor">@null</item> + <item name="tooltipBackgroundColor">@null</item> + + <!-- Holo-only color attributes --> + <item name="colorPressedHighlight">@color/holo_gray_light</item> + <item name="colorLongPressedHighlight">@color/holo_gray_bright</item> + <item name="colorFocusedHighlight">@color/holo_blue_dark</item> + <item name="colorMultiSelectHighlight">@color/holo_green_light</item> + <item name="colorActivatedHighlight">@color/holo_blue_dark</item> + </style> <!-- Variant of the holographic (light) theme that has a solid (opaque) action bar with an inverse color profile. The dark action bar sharply stands out against - the light content. --> + the light content. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.DarkActionBar"> <item name="windowContentOverlay">@drawable/ab_solid_shadow_holo</item> <item name="actionBarStyle">@style/Widget.Holo.Light.ActionBar.Solid.Inverse</item> @@ -773,7 +841,9 @@ please see themes_device_defaults.xml. <item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_holo_dark</item> </style> - <!-- Variant of the holographic (dark) theme with no action bar. --> + <!-- Variant of the holographic (dark) theme with no action bar. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.NoActionBar"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> @@ -781,7 +851,9 @@ please see themes_device_defaults.xml. <!-- Variant of the holographic (dark) theme that has no title bar and fills the entire screen. This theme - sets {@link android.R.attr#windowFullscreen} to true. --> + sets {@link android.R.attr#windowFullscreen} to true. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.NoActionBar.Fullscreen"> <item name="windowFullscreen">true</item> <item name="windowContentOverlay">@null</item> @@ -790,7 +862,9 @@ please see themes_device_defaults.xml. <!-- Variant of the holographic (dark) theme that has no title bar and fills the entire screen and extends into the display overscan region. This theme sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan} - to true. --> + to true. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.NoActionBar.Overscan"> <item name="windowFullscreen">true</item> <item name="windowOverscan">true</item> @@ -799,14 +873,18 @@ please see themes_device_defaults.xml. <!-- Variant of the holographic (dark) theme that has no title bar and translucent system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and - {@link android.R.attr#windowTranslucentNavigation} to true. --> + {@link android.R.attr#windowTranslucentNavigation} to true. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.NoActionBar.TranslucentDecor"> <item name="windowTranslucentStatus">true</item> <item name="windowTranslucentNavigation">true</item> <item name="windowContentOverlay">@null</item> </style> - <!-- Variant of the holographic (light) theme with no action bar. --> + <!-- Variant of the holographic (light) theme with no action bar. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.NoActionBar"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> @@ -814,7 +892,9 @@ please see themes_device_defaults.xml. <!-- Variant of the holographic (light) theme that has no title bar and fills the entire screen. This theme - sets {@link android.R.attr#windowFullscreen} to true. --> + sets {@link android.R.attr#windowFullscreen} to true. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.NoActionBar.Fullscreen"> <item name="windowFullscreen">true</item> <item name="windowContentOverlay">@null</item> @@ -823,7 +903,9 @@ please see themes_device_defaults.xml. <!-- Variant of the holographic (light) theme that has no title bar and fills the entire screen and extends into the display overscan region. This theme sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan} - to true. --> + to true. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.NoActionBar.Overscan"> <item name="windowFullscreen">true</item> <item name="windowOverscan">true</item> @@ -832,7 +914,9 @@ please see themes_device_defaults.xml. <!-- Variant of the holographic (light) theme that has no title bar and translucent system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and - {@link android.R.attr#windowTranslucentNavigation} to true. --> + {@link android.R.attr#windowTranslucentNavigation} to true. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.NoActionBar.TranslucentDecor"> <item name="windowTranslucentStatus">true</item> <item name="windowTranslucentNavigation">true</item> @@ -848,7 +932,9 @@ please see themes_device_defaults.xml. contents. You can set this theme on an activity if you would like to make an activity that looks like a Dialog. This is the default Dialog theme for applications targeting Honeycomb - or newer. --> + or newer. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Dialog"> <item name="windowFrame">@null</item> <item name="windowTitleStyle">@style/DialogWindowTitle.Holo</item> @@ -878,26 +964,34 @@ please see themes_device_defaults.xml. </style> <!-- Variant of Theme.Holo.Dialog that has a nice minimum width for - a regular dialog. --> + a regular dialog. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Dialog.MinWidth"> <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item> <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item> </style> - <!-- Variant of Theme.Holo.Dialog that does not include a title bar. --> + <!-- Variant of Theme.Holo.Dialog that does not include a title bar. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Dialog.NoActionBar"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> </style> <!-- Variant of Theme.Holo.Dialog.NoActionBar that has a nice minimum width for - a regular dialog. --> + a regular dialog. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Dialog.NoActionBar.MinWidth"> <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item> <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item> </style> - <!-- Variant of Theme.Holo.Dialog that has a fixed size. --> + <!-- Variant of Theme.Holo.Dialog that has a fixed size. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Dialog.FixedSize"> <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item> <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item> @@ -905,7 +999,9 @@ please see themes_device_defaults.xml. <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item> </style> - <!-- Variant of Theme.Holo.Dialog.NoActionBar that has a fixed size. --> + <!-- Variant of Theme.Holo.Dialog.NoActionBar that has a fixed size. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Dialog.NoActionBar.FixedSize"> <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item> <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item> @@ -915,7 +1011,9 @@ please see themes_device_defaults.xml. <!-- Variant of Theme.Holo.Dialog that does not include a frame (or background). The view hierarchy of the dialog is responsible for drawing all of - its pixels. --> + its pixels. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Dialog.NoFrame"> <item name="windowBackground">@color/transparent</item> <item name="windowFrame">@null</item> @@ -939,20 +1037,28 @@ please see themes_device_defaults.xml. {@link android.app.AlertDialog} class. This is basically a dialog but sets the background to empty so it can do two-tone backgrounds. For applications targeting Honeycomb or newer, this is the default - AlertDialog theme. --> + AlertDialog theme. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Dialog.Alert" parent="Theme.Holo.Dialog.BaseAlert" /> <!-- Theme for a window that will be displayed either full-screen on smaller screens (small, normal) or as a dialog on larger screens - (large, xlarge). --> + (large, xlarge). + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.DialogWhenLarge" parent="Theme.Holo" /> <!-- Theme for a window without a title bar that will be displayed either full-screen on smaller screens (small, normal) or as a dialog on larger screens - (large, xlarge). --> + (large, xlarge). + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.DialogWhenLarge.NoActionBar" parent="Theme.Holo.NoActionBar" /> - <!-- Theme for a presentation window on a secondary display. --> + <!-- Theme for a presentation window on a secondary display. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Dialog.Presentation" parent="Theme.Holo.NoActionBar.Fullscreen" /> <!-- Light holo dialog themes --> @@ -963,7 +1069,9 @@ please see themes_device_defaults.xml. contents. You can set this theme on an activity if you would like to make an activity that looks like a Dialog. This is the default Dialog theme for applications targeting Honeycomb - or newer. --> + or newer. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.Dialog"> <item name="windowFrame">@null</item> <item name="windowTitleStyle">@style/DialogWindowTitle.Holo.Light</item> @@ -993,26 +1101,34 @@ please see themes_device_defaults.xml. </style> <!-- Variant of Theme.Holo.Light.Dialog that has a nice minimum width for - a regular dialog. --> + a regular dialog. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.Dialog.MinWidth"> <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item> <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item> </style> - <!-- Variant of Theme.Holo.Light.Dialog that does not include a title bar. --> + <!-- Variant of Theme.Holo.Light.Dialog that does not include a title bar. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.Dialog.NoActionBar"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> </style> <!-- Variant of Theme.Holo.Light.Dialog.NoActionBar that has a nice minimum width for - a regular dialog. --> + a regular dialog. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.Dialog.NoActionBar.MinWidth"> <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item> <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item> </style> - <!-- Variant of Theme.Holo.Light.Dialog that has a fixed size. --> + <!-- Variant of Theme.Holo.Light.Dialog that has a fixed size. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.Dialog.FixedSize"> <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item> <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item> @@ -1020,7 +1136,9 @@ please see themes_device_defaults.xml. <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item> </style> - <!-- Variant of Theme.Holo.Light.Dialog.NoActionBar that has a fixed size. --> + <!-- Variant of Theme.Holo.Light.Dialog.NoActionBar that has a fixed size. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.Dialog.NoActionBar.FixedSize"> <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item> <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item> @@ -1030,12 +1148,16 @@ please see themes_device_defaults.xml. <!-- Theme for a window that will be displayed either full-screen on smaller screens (small, normal) or as a dialog on larger screens - (large, xlarge). --> + (large, xlarge). + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.DialogWhenLarge" parent="Theme.Holo.Light" /> <!-- Theme for a window without an action bar that will be displayed either full-screen on smaller screens (small, normal) or as a dialog on larger screens - (large, xlarge). --> + (large, xlarge). + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.DialogWhenLarge.NoActionBar" parent="Theme.Holo.Light.NoActionBar" /> <style name="Theme.Holo.Light.Dialog.BaseAlert"> @@ -1050,14 +1172,20 @@ please see themes_device_defaults.xml. {@link android.app.AlertDialog} class. This is basically a dialog but sets the background to empty so it can do two-tone backgrounds. For applications targeting Honeycomb or newer, this is the default - AlertDialog theme. --> + AlertDialog theme. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Holo.Light.Dialog.BaseAlert" /> - <!-- Theme for a presentation window on a secondary display. --> + <!-- Theme for a presentation window on a secondary display. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.Dialog.Presentation" parent="Theme.Holo.Light.NoActionBar.Fullscreen" /> <!-- Default holographic (dark) for windows that want to have the user's selected - wallpaper appear behind them. --> + wallpaper appear behind them. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Wallpaper"> <item name="windowBackground">@color/transparent</item> <item name="colorBackgroundCacheHint">@null</item> @@ -1065,7 +1193,9 @@ please see themes_device_defaults.xml. </style> <!--Default holographic (dark) for windows that want to have the user's selected - wallpaper appear behind them and without an action bar. --> + wallpaper appear behind them and without an action bar. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Wallpaper.NoTitleBar"> <item name="windowNoTitle">true</item> </style> @@ -1073,7 +1203,9 @@ please see themes_device_defaults.xml. <!-- Default holo dark theme for panel windows. This removes all extraneous window decorations, so you basically have an empty rectangle in which to place your content. It makes the window floating, with a transparent - background, and turns off dimming behind the window. --> + background, and turns off dimming behind the window. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Panel"> <item name="windowBackground">@color/transparent</item> <item name="colorBackgroundCacheHint">@null</item> @@ -1089,7 +1221,9 @@ please see themes_device_defaults.xml. <!-- Default holo light theme for panel windows. This removes all extraneous window decorations, so you basically have an empty rectangle in which to place your content. It makes the window floating, with a transparent - background, and turns off dimming behind the window. --> + background, and turns off dimming behind the window. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.Panel"> <item name="windowBackground">@color/transparent</item> <item name="colorBackgroundCacheHint">@null</item> @@ -1105,7 +1239,9 @@ please see themes_device_defaults.xml. <!-- Default theme for holo style input methods, which is used by the {@link android.inputmethodservice.InputMethodService} class. this inherits from Theme.Panel, but sets up IME appropriate animations - and a few custom attributes. --> + and a few custom attributes. + + @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.InputMethod" parent="Theme.Holo.Light.Panel"> <item name="windowAnimationStyle">@style/Animation.InputMethod</item> <item name="imeFullscreenBackground">@drawable/screen_background_selector_light</item> @@ -1113,17 +1249,19 @@ please see themes_device_defaults.xml. <item name="imeExtractExitAnimation">@anim/input_method_extract_exit</item> </style> - + <!-- @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.SearchBar" parent="Theme.Holo.Panel"> <item name="actionModeBackground">@drawable/cab_background_top_holo_dark</item> <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item> </style> + <!-- @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.SearchBar" parent="Theme.Holo.Light.Panel"> <item name="actionModeBackground">@drawable/cab_background_top_holo_light</item> <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item> </style> + <!-- @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.CompactMenu"> <!-- Menu/item attributes --> <item name="itemTextAppearance">?attr/textAppearanceMedium</item> @@ -1132,6 +1270,7 @@ please see themes_device_defaults.xml. <item name="background">@null</item> </style> + <!-- @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. --> <style name="Theme.Holo.Light.CompactMenu"> <!-- Menu/item attributes --> <item name="itemTextAppearance">?attr/textAppearanceMedium</item> diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml index 15d8fb7b184d..6ae0ef3da225 100644 --- a/core/res/res/values/themes_material.xml +++ b/core/res/res/values/themes_material.xml @@ -384,7 +384,6 @@ please see themes_device_defaults.xml. <!-- DatePicker dialog theme --> <item name="datePickerDialogTheme">@style/ThemeOverlay.Material.Dialog.DatePicker</item> - <!-- TODO: This belongs in a FastScroll style --> <item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_material</item> <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_material</item> <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_material</item> diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java index d425dcc7f592..42c9139e04e2 100644 --- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java @@ -25,6 +25,7 @@ import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP; import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING; import static android.os.BatteryStats.Uid.UID_PROCESS_TYPES; +import static com.android.internal.os.BatteryStatsImpl.Constants.KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS; import static com.android.internal.os.BatteryStatsImpl.Constants.KEY_TRACK_CPU_TIMES_BY_PROC_STATE; import static junit.framework.Assert.assertNotNull; @@ -101,6 +102,11 @@ public class BstatsCpuTimesValidationTest { private static final int WORK_DURATION_MS = 2000; + private static final String DESIRED_PROC_STATE_CPU_TIMES_DELAY = "0"; + + private static boolean sBatteryStatsConstsUpdated; + private static String sOriginalBatteryStatsConsts; + private static Context sContext; private static UiDevice sUiDevice; private static int sTestPkgUid; @@ -117,13 +123,43 @@ public class BstatsCpuTimesValidationTest { PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0); sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_PKG, 0); checkCpuTimesAvailability(); + if (sPerProcStateTimesAvailable && sCpuFreqTimesAvailable) { + setDesiredReadyDelay(); + } } @AfterClass public static void tearDownOnce() throws Exception { + if (sBatteryStatsConstsUpdated) { + Settings.Global.putString(sContext.getContentResolver(), + Settings.Global.BATTERY_STATS_CONSTANTS, sOriginalBatteryStatsConsts); + } batteryReset(); } + private static void setDesiredReadyDelay() { + sOriginalBatteryStatsConsts = Settings.Global.getString(sContext.getContentResolver(), + Settings.Global.BATTERY_STATS_CONSTANTS); + String newBatteryStatsConstants; + final String newConstant = KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS + + "=" + DESIRED_PROC_STATE_CPU_TIMES_DELAY; + if (sOriginalBatteryStatsConsts == null || "null".equals(sOriginalBatteryStatsConsts)) { + // battery_stats_constants is initially empty, so just assign the desired value. + newBatteryStatsConstants = newConstant; + } else if (sOriginalBatteryStatsConsts.contains(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS)) { + // battery_stats_constants contains delay duration, so replace it + // with the desired value. + newBatteryStatsConstants = sOriginalBatteryStatsConsts.replaceAll( + KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS + "=\\d+", newConstant); + } else { + // battery_stats_constants didn't contain any delay, so append the desired value. + newBatteryStatsConstants = sOriginalBatteryStatsConsts + "," + newConstant; + } + Settings.Global.putString(sContext.getContentResolver(), + Settings.Global.BATTERY_STATS_CONSTANTS, newBatteryStatsConstants); + sBatteryStatsConstsUpdated = true; + } + // Checks cpu freq times of system uid as an indication of whether /proc/uid_time_in_state // and /proc/uid/<uid>/time_in_state kernel nodes are available. private static void checkCpuTimesAvailability() throws Exception { @@ -132,9 +168,9 @@ public class BstatsCpuTimesValidationTest { batteryOff(); final long[] totalCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID); sCpuFreqTimesAvailable = totalCpuTimes != null; - final long[] fgSvcCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID, + final long[] fgCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID, PROCESS_STATE_FOREGROUND); - sPerProcStateTimesAvailable = fgSvcCpuTimes != null; + sPerProcStateTimesAvailable = fgCpuTimes != null; } @Test diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java index cb05253c6f57..6d5c7e7749e8 100644 --- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java +++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java @@ -160,8 +160,8 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { } @Override - public Future<?> scheduleReadProcStateCpuTimes( - boolean onBattery, boolean onBatteryScreenOff) { + public Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, + boolean onBatteryScreenOff, long delayMillis) { return null; } diff --git a/docs/html/reference/images/text/style/typefacespan.png b/docs/html/reference/images/text/style/typefacespan.png Binary files differindex 67e2cf9b0468..1651c390e715 100644 --- a/docs/html/reference/images/text/style/typefacespan.png +++ b/docs/html/reference/images/text/style/typefacespan.png diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java index 41d36986dfe2..2812abe067f7 100644 --- a/graphics/java/android/graphics/drawable/RippleBackground.java +++ b/graphics/java/android/graphics/drawable/RippleBackground.java @@ -78,9 +78,10 @@ class RippleBackground extends RippleComponent { } private void onStateChanged() { - float newOpacity = 0.0f; - if (mHovered) newOpacity += .25f; - if (mFocused) newOpacity += .75f; + // Hover = .2 * alpha + // Focus = .6 * alpha + // Focused + Hovered = .6 * alpha + float newOpacity = mFocused ? .6f : mHovered ? .2f : 0f; if (mAnimator != null) { mAnimator.cancel(); mAnimator = null; diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index d194796ec1c5..7d2ad9125f40 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -23,6 +23,7 @@ import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import android.Manifest; import android.annotation.NonNull; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; @@ -30,6 +31,7 @@ import android.annotation.SystemService; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -63,6 +65,7 @@ import java.util.List; * location will be obfuscated to a coarse level of accuracy. */ @SystemService(Context.LOCATION_SERVICE) +@RequiresFeature(PackageManager.FEATURE_LOCATION) public class LocationManager { private static final String TAG = "LocationManager"; diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java index a015732ddfdd..dee94c681e87 100644 --- a/media/java/android/media/midi/MidiManager.java +++ b/media/java/android/media/midi/MidiManager.java @@ -16,9 +16,11 @@ package android.media.midi; +import android.annotation.RequiresFeature; import android.annotation.SystemService; import android.bluetooth.BluetoothDevice; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.IBinder; import android.os.Bundle; @@ -32,6 +34,7 @@ import java.util.concurrent.ConcurrentHashMap; * This class is the public application interface to the MIDI service. */ @SystemService(Context.MIDI_SERVICE) +@RequiresFeature(PackageManager.FEATURE_MIDI) public final class MidiManager { private static final String TAG = "MidiManager"; diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index b380ac53ddad..c5c116982b42 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -1048,15 +1048,20 @@ public class AccessPoint implements Comparable<AccessPoint> { if (newLevel > 0 && newLevel != oldLevel) { // Only update labels on visible rssi changes updateSpeed(); - if (mAccessPointListener != null) { - ThreadUtils.postOnMainThread(() -> mAccessPointListener.onLevelChanged(this)); - } - } + ThreadUtils.postOnMainThread(() -> { + if (mAccessPointListener != null) { + mAccessPointListener.onLevelChanged(this); + } + }); - if (mAccessPointListener != null) { - ThreadUtils.postOnMainThread(() -> mAccessPointListener.onAccessPointChanged(this)); } + ThreadUtils.postOnMainThread(() -> { + if (mAccessPointListener != null) { + mAccessPointListener.onAccessPointChanged(this); + } + }); + if (!scanResults.isEmpty()) { ScanResult result = scanResults.iterator().next(); @@ -1102,10 +1107,18 @@ public class AccessPoint implements Comparable<AccessPoint> { mNetworkInfo = null; } if (updated && mAccessPointListener != null) { - ThreadUtils.postOnMainThread(() -> mAccessPointListener.onAccessPointChanged(this)); + ThreadUtils.postOnMainThread(() -> { + if (mAccessPointListener != null) { + mAccessPointListener.onAccessPointChanged(this); + } + }); if (oldLevel != getLevel() /* current level */) { - ThreadUtils.postOnMainThread(() -> mAccessPointListener.onLevelChanged(this)); + ThreadUtils.postOnMainThread(() -> { + if (mAccessPointListener != null) { + mAccessPointListener.onLevelChanged(this); + } + }); } } @@ -1115,9 +1128,11 @@ public class AccessPoint implements Comparable<AccessPoint> { void update(@Nullable WifiConfiguration config) { mConfig = config; networkId = config != null ? config.networkId : WifiConfiguration.INVALID_NETWORK_ID; - if (mAccessPointListener != null) { - ThreadUtils.postOnMainThread(() -> mAccessPointListener.onAccessPointChanged(this)); - } + ThreadUtils.postOnMainThread(() -> { + if (mAccessPointListener != null) { + mAccessPointListener.onAccessPointChanged(this); + } + }); } @VisibleForTesting diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java index ebafc594c122..017d37388340 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java @@ -31,7 +31,6 @@ import android.content.SharedPreferences; import android.util.Pair; import com.android.settingslib.SettingsLibRobolectricTestRunner; -import com.google.common.truth.Platform; import org.junit.Before; import org.junit.Test; @@ -160,18 +159,23 @@ public class SharedPreferenceLoggerTest { } private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, Class clazz) { - return pair -> pair.first == tag && Platform.isInstanceOfType(pair.second, clazz); + return pair -> pair.first == tag && isInstanceOfType(pair.second, clazz); } private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, boolean bool) { return pair -> pair.first == tag - && Platform.isInstanceOfType(pair.second, Integer.class) + && isInstanceOfType(pair.second, Integer.class) && pair.second.equals((bool ? 1 : 0)); } private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, int val) { return pair -> pair.first == tag - && Platform.isInstanceOfType(pair.second, Integer.class) + && isInstanceOfType(pair.second, Integer.class) && pair.second.equals(val); } + + /** Returns true if the instance is assignable to the type Clazz. */ + private static boolean isInstanceOfType(Object instance, Class<?> clazz) { + return clazz.isInstance(instance); + } } diff --git a/packages/SystemUI/res/drawable/smart_reply_button_background.xml b/packages/SystemUI/res/drawable/smart_reply_button_background.xml index 1cd1451008b4..c5ac67beb521 100644 --- a/packages/SystemUI/res/drawable/smart_reply_button_background.xml +++ b/packages/SystemUI/res/drawable/smart_reply_button_background.xml @@ -20,7 +20,9 @@ android:color="@color/notification_ripple_untinted_color"> <item> <shape android:shape="rectangle"> - <corners android:radius="@dimen/smart_reply_button_corner_radius"/> + <!-- Use non-zero corner radius to work around b/73285195. The actual corner radius is + set dynamically at runtime in SmartReplyView. --> + <corners android:radius="1dp"/> <solid android:color="@color/smart_reply_button_background"/> </shape> </item> diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml index a3118b0a5d91..25b117fb2e33 100644 --- a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml +++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml @@ -63,6 +63,7 @@ android:src="@drawable/screen_pinning_bg_circ" /> <ImageView + android:id="@+id/screen_pinning_back_icon" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingEnd="@dimen/screen_pinning_request_nav_side_padding" @@ -105,6 +106,7 @@ android:src="@drawable/screen_pinning_bg_circ" /> <ImageView + android:id="@+id/screen_pinning_home_icon" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingEnd="@dimen/screen_pinning_request_nav_side_padding" diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml index 61fe906d65fc..37a1a90b6474 100644 --- a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml +++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml @@ -59,6 +59,7 @@ android:src="@drawable/screen_pinning_bg_circ" /> <ImageView + android:id="@+id/screen_pinning_back_icon" android:layout_height="match_parent" android:layout_width="match_parent" android:scaleType="center" @@ -99,6 +100,7 @@ android:src="@drawable/screen_pinning_bg_circ" /> <ImageView + android:id="@+id/screen_pinning_home_icon" android:layout_height="match_parent" android:layout_width="match_parent" android:scaleType="center" diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml index d1ca2ce5935c..bac02aa34ed9 100644 --- a/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml +++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml @@ -61,6 +61,7 @@ android:src="@drawable/screen_pinning_bg_circ" /> <ImageView + android:id="@+id/screen_pinning_back_icon" android:layout_height="match_parent" android:layout_width="match_parent" android:scaleType="center" @@ -103,6 +104,7 @@ android:src="@drawable/screen_pinning_bg_circ" /> <ImageView + android:id="@+id/screen_pinning_home_icon" android:layout_height="match_parent" android:layout_width="match_parent" android:scaleType="center" diff --git a/packages/SystemUI/res/layout/smart_reply_button.xml b/packages/SystemUI/res/layout/smart_reply_button.xml index 4ac41d5cf6c3..3c6edcd8a917 100644 --- a/packages/SystemUI/res/layout/smart_reply_button.xml +++ b/packages/SystemUI/res/layout/smart_reply_button.xml @@ -16,17 +16,19 @@ ~ limitations under the License --> +<!-- android:paddingHorizontal is set dynamically in SmartReplyView. --> <Button xmlns:android="http://schemas.android.com/apk/res/android" style="@android:style/Widget.Material.Button.Borderless.Small" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/smart_reply_button_spacing" + android:layout_height="match_parent" + android:minWidth="0dp" + android:minHeight="@dimen/smart_reply_button_min_height" android:paddingVertical="@dimen/smart_reply_button_padding_vertical" - android:paddingHorizontal="@dimen/smart_reply_button_corner_radius" android:background="@drawable/smart_reply_button_background" android:gravity="center" android:fontFamily="sans-serif" android:textSize="@dimen/smart_reply_button_font_size" + android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra" android:textColor="@color/smart_reply_button_text" android:textStyle="normal" - android:singleLine="true"/>
\ No newline at end of file + android:ellipsize="none"/>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/smart_reply_view.xml b/packages/SystemUI/res/layout/smart_reply_view.xml index 6d5338697161..6f21787a1524 100644 --- a/packages/SystemUI/res/layout/smart_reply_view.xml +++ b/packages/SystemUI/res/layout/smart_reply_view.xml @@ -19,9 +19,12 @@ <!-- LinearLayout --> <com.android.systemui.statusbar.policy.SmartReplyView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/smart_reply_view" android:layout_height="wrap_content" android:layout_width="wrap_content" - android:layout_gravity="end"> + systemui:spacing="@dimen/smart_reply_button_spacing" + systemui:singleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_single_line" + systemui:doubleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_double_line"> <!-- smart_reply_button(s) will be added here. --> </com.android.systemui.statusbar.policy.SmartReplyView>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index a923f0b8c332..f0a5fe421b84 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -130,5 +130,11 @@ <attr name="darkIconTheme" format="reference" /> <attr name="wallpaperTextColor" format="reference|color" /> <attr name="wallpaperTextColorSecondary" format="reference|color" /> + + <declare-styleable name="SmartReplyView"> + <attr name="spacing" format="dimension" /> + <attr name="singleLineButtonPaddingHorizontal" format="dimension" /> + <attr name="doubleLineButtonPaddingHorizontal" format="dimension" /> + </declare-styleable> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index be8e990fb075..c054d16644e4 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -156,9 +156,8 @@ <color name="zen_introduction">#ffffffff</color> - - <color name="smart_reply_button_text">#ff4285f4</color><!-- blue 500 --> - <color name="smart_reply_button_background">#fff7f7f7</color> + <color name="smart_reply_button_text">#de000000</color> <!-- 87% black --> + <color name="smart_reply_button_background">#fff2f2f2</color> <!-- Fingerprint dialog colors --> <color name="fingerprint_dialog_bg_color">#f4ffffff</color> <!-- 96% white --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index d17cd21b217c..3ff553e156c7 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -887,10 +887,13 @@ <dimen name="home_padding">16dp</dimen> <!-- Smart reply button --> - <dimen name="smart_reply_button_corner_radius">24dip</dimen> <dimen name="smart_reply_button_spacing">8dp</dimen> - <dimen name="smart_reply_button_padding_vertical">4dp</dimen> + <dimen name="smart_reply_button_padding_vertical">10dp</dimen> + <dimen name="smart_reply_button_padding_horizontal_single_line">12dp</dimen> + <dimen name="smart_reply_button_padding_horizontal_double_line">16dp</dimen> + <dimen name="smart_reply_button_min_height">40dp</dimen> <dimen name="smart_reply_button_font_size">14sp</dimen> + <dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. --> <dimen name="fingerprint_dialog_icon_size">44dp</dimen> <dimen name="fingerprint_dialog_fp_icon_size">60dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java index b9919a3f5c12..e24135775e79 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java @@ -176,6 +176,7 @@ public class QSFooterImpl extends FrameLayout implements QSFooter, .addFloat(mActionsContainer, "alpha", 0, 1) .addFloat(mDragHandle, "translationY", mDragHandleExpandOffset, 0) .addFloat(mDragHandle, "alpha", 1, 0) + .setStartDelay(0.15f) .build(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index 57f7818eae58..3dd6e353c924 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -36,6 +36,7 @@ import android.view.accessibility.AccessibilityManager; import android.view.animation.DecelerateInterpolator; import android.widget.Button; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -255,6 +256,11 @@ public class ScreenPinningRequest implements View.OnClickListener { : R.string.screen_pinning_description_recents_invisible; } + ((ImageView) mLayout.findViewById(R.id.screen_pinning_back_icon)) + .setImageDrawable(navigationBarView.getBackDrawable(mContext)); + ((ImageView) mLayout.findViewById(R.id.screen_pinning_home_icon)) + .setImageDrawable(navigationBarView.getHomeDrawable(mContext)); + ((TextView) mLayout.findViewById(R.id.screen_pinning_description)) .setText(descriptionStringResId); final int backBgVisibility = touchExplorationEnabled ? View.INVISIBLE : View.VISIBLE; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java index 8970ea0c110b..4454ef9f411c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java @@ -149,6 +149,10 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture } public boolean onInterceptTouchEvent(MotionEvent event) { + if (mNavigationBarView.inScreenPinning()) { + return false; + } + int action = event.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: { @@ -177,6 +181,10 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture } public boolean onTouchEvent(MotionEvent event) { + if (mNavigationBarView.inScreenPinning()) { + return false; + } + // The same down event was just sent on intercept and therefore can be ignored here boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN && mOverviewProxyService.getProxy() != null; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index c047670f95db..285980b39020 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -67,6 +67,7 @@ import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.statusbar.phone.NavGesture; import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper; import com.android.systemui.recents.RecentsOnboarding; +import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.NavigationBarCompat; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.policy.DeadZone; @@ -403,28 +404,17 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav } private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) { - final boolean quickStepEnabled = isQuickStepSwipeUpEnabled() || isQuickScrubEnabled(); if (oldConfig.orientation != newConfig.orientation || oldConfig.densityDpi != newConfig.densityDpi) { mDockedIcon = getDrawable(ctx, R.drawable.ic_sysbar_docked, R.drawable.ic_sysbar_docked_dark); - mHomeDefaultIcon = quickStepEnabled - ? getDrawable(ctx, R.drawable.ic_sysbar_home_quick_step, - R.drawable.ic_sysbar_home_quick_step_dark) - : getDrawable(ctx, R.drawable.ic_sysbar_home, R.drawable.ic_sysbar_home_dark); + mHomeDefaultIcon = getHomeDrawable(ctx); } if (oldConfig.densityDpi != newConfig.densityDpi || oldConfig.getLayoutDirection() != newConfig.getLayoutDirection()) { - mBackIcon = quickStepEnabled - ? getDrawable(ctx, R.drawable.ic_sysbar_back_quick_step, - R.drawable.ic_sysbar_back_quick_step_dark) - : getDrawable(ctx, R.drawable.ic_sysbar_back, R.drawable.ic_sysbar_back_dark); + mBackIcon = getBackDrawable(ctx); mBackLandIcon = mBackIcon; - mBackAltIcon = quickStepEnabled - ? getDrawable(ctx, R.drawable.ic_sysbar_back_ime_quick_step, - R.drawable.ic_sysbar_back_ime_quick_step_dark) - : getDrawable(ctx, R.drawable.ic_sysbar_back_ime, - R.drawable.ic_sysbar_back_ime_dark); + mBackAltIcon = getBackImeDrawable(ctx); mBackAltLandIcon = mBackAltIcon; mRecentIcon = getDrawable(ctx, R.drawable.ic_sysbar_recent, R.drawable.ic_sysbar_recent_dark); @@ -450,6 +440,33 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav } } + public KeyButtonDrawable getBackDrawable(Context ctx) { + return chooseNavigationIconDrawable(ctx, R.drawable.ic_sysbar_back, + R.drawable.ic_sysbar_back_dark, R.drawable.ic_sysbar_back_quick_step, + R.drawable.ic_sysbar_back_quick_step_dark); + } + + public KeyButtonDrawable getBackImeDrawable(Context ctx) { + return chooseNavigationIconDrawable(ctx, R.drawable.ic_sysbar_back_ime, + R.drawable.ic_sysbar_back_ime_dark, R.drawable.ic_sysbar_back_ime_quick_step, + R.drawable.ic_sysbar_back_ime_quick_step_dark); + } + + public KeyButtonDrawable getHomeDrawable(Context ctx) { + return chooseNavigationIconDrawable(ctx, R.drawable.ic_sysbar_home, + R.drawable.ic_sysbar_home_dark, R.drawable.ic_sysbar_home_quick_step, + R.drawable.ic_sysbar_home_quick_step_dark); + } + + private KeyButtonDrawable chooseNavigationIconDrawable(Context ctx, @DrawableRes int iconLight, + @DrawableRes int iconDark, @DrawableRes int quickStepIconLight, + @DrawableRes int quickStepIconDark) { + final boolean quickStepEnabled = isQuickStepSwipeUpEnabled() || isQuickScrubEnabled(); + return quickStepEnabled + ? getDrawable(ctx, quickStepIconLight, quickStepIconDark) + : getDrawable(ctx, iconLight, iconDark); + } + private KeyButtonDrawable getDrawable(Context ctx, @DrawableRes int lightIcon, @DrawableRes int darkIcon) { return getDrawable(ctx, ctx, lightIcon, darkIcon); @@ -558,7 +575,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav mDisabledFlags = disabledFlags; - final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0); + boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0); // Always disable recents when alternate car mode UI is active. boolean disableRecent = mUseCarModeUi @@ -567,20 +584,21 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0) && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0); - if ((disableRecent || disableBack) && inScreenPinning()) { - // Don't hide back and recents buttons when in screen pinning mode, as they are used for - // exiting. - disableBack = false; - disableRecent = false; - } - + // When screen pinning, don't hide back and home when connected service or back and + // recents buttons when disconnected from launcher service in screen pinning mode, + // as they are used for exiting. if (mOverviewProxyService.getProxy() != null) { - // When overview is connected to the launcher service, disable the recents button by - // default unless overwritten by interaction flags. Similar with the back button but - // shown by default. + // Use interaction flags to show/hide navigation buttons but will be shown if required + // to exit screen pinning. final int flags = mOverviewProxyService.getInteractionFlags(); disableRecent |= (flags & FLAG_SHOW_OVERVIEW_BUTTON) == 0; - disableBack |= (flags & FLAG_HIDE_BACK_BUTTON) != 0; + if (inScreenPinning()) { + disableBack = disableHome = false; + } else { + disableBack |= (flags & FLAG_HIDE_BACK_BUTTON) != 0; + } + } else if (inScreenPinning()) { + disableBack = disableRecent = false; } ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons); @@ -598,13 +616,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE); } - private boolean inScreenPinning() { - try { - return ActivityManager.getService().getLockTaskModeState() - == ActivityManager.LOCK_TASK_MODE_PINNED; - } catch (RemoteException e) { - return false; - } + public boolean inScreenPinning() { + return ActivityManagerWrapper.getInstance().isLockToAppActive(); } public void setLayoutTransitionsEnabled(boolean enabled) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java index 57fc03cb7308..790135fc03ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java @@ -4,27 +4,105 @@ import android.app.PendingIntent; import android.app.RemoteInput; import android.content.Context; import android.content.Intent; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.RippleDrawable; import android.os.Bundle; +import android.text.Layout; +import android.text.TextPaint; +import android.text.method.TransformationMethod; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import android.widget.Button; -import android.widget.LinearLayout; +import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.R; +import java.text.BreakIterator; +import java.util.Comparator; +import java.util.PriorityQueue; + /** View which displays smart reply buttons in notifications. */ -public class SmartReplyView extends LinearLayout { +public class SmartReplyView extends ViewGroup { private static final String TAG = "SmartReplyView"; + private static final int MEASURE_SPEC_ANY_WIDTH = + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + + private static final Comparator<View> DECREASING_MEASURED_WIDTH_WITHOUT_PADDING_COMPARATOR = + (v1, v2) -> ((v2.getMeasuredWidth() - v2.getPaddingLeft() - v2.getPaddingRight()) + - (v1.getMeasuredWidth() - v1.getPaddingLeft() - v1.getPaddingRight())); + + private static final int SQUEEZE_FAILED = -1; + private final SmartReplyConstants mConstants; + /** Spacing to be applied between views. */ + private final int mSpacing; + + /** Horizontal padding of smart reply buttons if all of them use only one line of text. */ + private final int mSingleLineButtonPaddingHorizontal; + + /** Horizontal padding of smart reply buttons if at least one of them uses two lines of text. */ + private final int mDoubleLineButtonPaddingHorizontal; + + /** Increase in width of a smart reply button as a result of using two lines instead of one. */ + private final int mSingleToDoubleLineButtonWidthIncrease; + + private final BreakIterator mBreakIterator; + + private PriorityQueue<Button> mCandidateButtonQueueForSqueezing; + public SmartReplyView(Context context, AttributeSet attrs) { super(context, attrs); mConstants = Dependency.get(SmartReplyConstants.class); + + int spacing = 0; + int singleLineButtonPaddingHorizontal = 0; + int doubleLineButtonPaddingHorizontal = 0; + + final TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.SmartReplyView, + 0, 0); + final int length = arr.getIndexCount(); + for (int i = 0; i < length; i++) { + int attr = arr.getIndex(i); + switch (attr) { + case R.styleable.SmartReplyView_spacing: + spacing = arr.getDimensionPixelSize(i, 0); + break; + case R.styleable.SmartReplyView_singleLineButtonPaddingHorizontal: + singleLineButtonPaddingHorizontal = arr.getDimensionPixelSize(i, 0); + break; + case R.styleable.SmartReplyView_doubleLineButtonPaddingHorizontal: + doubleLineButtonPaddingHorizontal = arr.getDimensionPixelSize(i, 0); + break; + } + } + arr.recycle(); + + mSpacing = spacing; + mSingleLineButtonPaddingHorizontal = singleLineButtonPaddingHorizontal; + mDoubleLineButtonPaddingHorizontal = doubleLineButtonPaddingHorizontal; + mSingleToDoubleLineButtonWidthIncrease = + 2 * (doubleLineButtonPaddingHorizontal - singleLineButtonPaddingHorizontal); + + mBreakIterator = BreakIterator.getLineInstance(); + reallocateCandidateButtonQueueForSqueezing(); + } + + private void reallocateCandidateButtonQueueForSqueezing() { + // Instead of clearing the priority queue, we re-allocate so that it would fit all buttons + // exactly. This avoids (1) wasting memory because PriorityQueue never shrinks and + // (2) growing in onMeasure. + // The constructor throws an IllegalArgument exception if initial capacity is less than 1. + mCandidateButtonQueueForSqueezing = new PriorityQueue<>( + Math.max(getChildCount(), 1), DECREASING_MEASURED_WIDTH_WITHOUT_PADDING_COMPARATOR); } public void setRepliesFromRemoteInput(RemoteInput remoteInput, PendingIntent pendingIntent) { @@ -39,6 +117,7 @@ public class SmartReplyView extends LinearLayout { } } } + reallocateCandidateButtonQueueForSqueezing(); } public static SmartReplyView inflate(Context context, ViewGroup root) { @@ -46,7 +125,8 @@ public class SmartReplyView extends LinearLayout { LayoutInflater.from(context).inflate(R.layout.smart_reply_view, root, false); } - private static Button inflateReplyButton(Context context, ViewGroup root, CharSequence choice, + @VisibleForTesting + static Button inflateReplyButton(Context context, ViewGroup root, CharSequence choice, RemoteInput remoteInput, PendingIntent pendingIntent) { Button b = (Button) LayoutInflater.from(context).inflate( R.layout.smart_reply_button, root, false); @@ -65,4 +145,376 @@ public class SmartReplyView extends LinearLayout { }); return b; } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(mContext, attrs); + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + } + + @Override + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams params) { + return new LayoutParams(params.width, params.height); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int targetWidth = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED + ? Integer.MAX_VALUE : MeasureSpec.getSize(widthMeasureSpec); + + // Mark all buttons as hidden and un-squeezed. + resetButtonsLayoutParams(); + + if (!mCandidateButtonQueueForSqueezing.isEmpty()) { + Log.wtf(TAG, "Single line button queue leaked between onMeasure calls"); + mCandidateButtonQueueForSqueezing.clear(); + } + + int measuredWidth = mPaddingLeft + mPaddingRight; + int maxChildHeight = 0; + int displayedChildCount = 0; + int buttonPaddingHorizontal = mSingleLineButtonPaddingHorizontal; + + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (child.getVisibility() != View.VISIBLE || !(child instanceof Button)) { + continue; + } + + child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(), + buttonPaddingHorizontal, child.getPaddingBottom()); + child.measure(MEASURE_SPEC_ANY_WIDTH, heightMeasureSpec); + + final int lineCount = ((Button) child).getLineCount(); + if (lineCount < 1 || lineCount > 2) { + // If smart reply has no text, or more than two lines, then don't show it. + continue; + } + + if (lineCount == 1) { + mCandidateButtonQueueForSqueezing.add((Button) child); + } + + // Remember the current measurements in case the current button doesn't fit in. + final int originalMaxChildHeight = maxChildHeight; + final int originalMeasuredWidth = measuredWidth; + final int originalButtonPaddingHorizontal = buttonPaddingHorizontal; + + final int spacing = displayedChildCount == 0 ? 0 : mSpacing; + final int childWidth = child.getMeasuredWidth(); + final int childHeight = child.getMeasuredHeight(); + measuredWidth += spacing + childWidth; + maxChildHeight = Math.max(maxChildHeight, childHeight); + + // Do we need to increase the number of lines in smart reply buttons to two? + final boolean increaseToTwoLines = + buttonPaddingHorizontal == mSingleLineButtonPaddingHorizontal + && (lineCount == 2 || measuredWidth > targetWidth); + if (increaseToTwoLines) { + measuredWidth += (displayedChildCount + 1) * mSingleToDoubleLineButtonWidthIncrease; + buttonPaddingHorizontal = mDoubleLineButtonPaddingHorizontal; + } + + // If the last button doesn't fit into the remaining width, try squeezing preceding + // smart reply buttons. + if (measuredWidth > targetWidth) { + // Keep squeezing preceding and current smart reply buttons until they all fit. + while (measuredWidth > targetWidth + && !mCandidateButtonQueueForSqueezing.isEmpty()) { + final Button candidate = mCandidateButtonQueueForSqueezing.poll(); + final int squeezeReduction = squeezeButton(candidate, heightMeasureSpec); + if (squeezeReduction != SQUEEZE_FAILED) { + maxChildHeight = Math.max(maxChildHeight, candidate.getMeasuredHeight()); + measuredWidth -= squeezeReduction; + } + } + + // If the current button still doesn't fit after squeezing all buttons, undo the + // last squeezing round. + if (measuredWidth > targetWidth) { + measuredWidth = originalMeasuredWidth; + maxChildHeight = originalMaxChildHeight; + buttonPaddingHorizontal = originalButtonPaddingHorizontal; + + // Mark all buttons from the last squeezing round as "failed to squeeze", so + // that they're re-measured without squeezing later. + markButtonsWithPendingSqueezeStatusAs(LayoutParams.SQUEEZE_STATUS_FAILED, i); + + // The current button doesn't fit, so there's no point in measuring further + // buttons. + break; + } + + // The current button fits, so mark all squeezed buttons as "successfully squeezed" + // to prevent them from being un-squeezed in a subsequent squeezing round. + markButtonsWithPendingSqueezeStatusAs(LayoutParams.SQUEEZE_STATUS_SUCCESSFUL, i); + } + + lp.show = true; + displayedChildCount++; + } + + // We're done squeezing buttons, so we can clear the priority queue. + mCandidateButtonQueueForSqueezing.clear(); + + // Finally, we need to update corner radius and re-measure some buttons. + updateCornerRadiusAndRemeasureButtonsIfNecessary(buttonPaddingHorizontal, maxChildHeight); + + setMeasuredDimension( + resolveSize(Math.max(getSuggestedMinimumWidth(), measuredWidth), widthMeasureSpec), + resolveSize(Math.max(getSuggestedMinimumHeight(), + mPaddingTop + maxChildHeight + mPaddingBottom), heightMeasureSpec)); + } + + private void resetButtonsLayoutParams() { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + lp.show = false; + lp.squeezeStatus = LayoutParams.SQUEEZE_STATUS_NONE; + } + } + + private int squeezeButton(Button button, int heightMeasureSpec) { + final int estimatedOptimalTextWidth = estimateOptimalSqueezedButtonTextWidth(button); + if (estimatedOptimalTextWidth == SQUEEZE_FAILED) { + return SQUEEZE_FAILED; + } + return squeezeButtonToTextWidth(button, heightMeasureSpec, estimatedOptimalTextWidth); + } + + private int estimateOptimalSqueezedButtonTextWidth(Button button) { + // Find a line-break point in the middle of the smart reply button text. + final String rawText = button.getText().toString(); + + // The button sometimes has a transformation affecting text layout (e.g. all caps). + final TransformationMethod transformation = button.getTransformationMethod(); + final String text = transformation == null ? + rawText : transformation.getTransformation(rawText, button).toString(); + final int length = text.length(); + mBreakIterator.setText(text); + + if (mBreakIterator.preceding(length / 2) == BreakIterator.DONE) { + if (mBreakIterator.next() == BreakIterator.DONE) { + // Can't find a single possible line break in either direction. + return SQUEEZE_FAILED; + } + } + + final TextPaint paint = button.getPaint(); + final int initialPosition = mBreakIterator.current(); + final float initialLeftTextWidth = Layout.getDesiredWidth(text, 0, initialPosition, paint); + final float initialRightTextWidth = + Layout.getDesiredWidth(text, initialPosition, length, paint); + float optimalTextWidth = Math.max(initialLeftTextWidth, initialRightTextWidth); + + if (initialLeftTextWidth != initialRightTextWidth) { + // See if there's a better line-break point (leading to a more narrow button) in + // either left or right direction. + final boolean moveLeft = initialLeftTextWidth > initialRightTextWidth; + final int maxSqueezeRemeasureAttempts = mConstants.getMaxSqueezeRemeasureAttempts(); + for (int i = 0; i < maxSqueezeRemeasureAttempts; i++) { + final int newPosition = + moveLeft ? mBreakIterator.previous() : mBreakIterator.next(); + if (newPosition == BreakIterator.DONE) { + break; + } + + final float newLeftTextWidth = Layout.getDesiredWidth(text, 0, newPosition, paint); + final float newRightTextWidth = + Layout.getDesiredWidth(text, newPosition, length, paint); + final float newOptimalTextWidth = Math.max(newLeftTextWidth, newRightTextWidth); + if (newOptimalTextWidth < optimalTextWidth) { + optimalTextWidth = newOptimalTextWidth; + } else { + break; + } + + boolean tooFar = moveLeft + ? newLeftTextWidth <= newRightTextWidth + : newLeftTextWidth >= newRightTextWidth; + if (tooFar) { + break; + } + } + } + + return (int) Math.ceil(optimalTextWidth); + } + + private int squeezeButtonToTextWidth(Button button, int heightMeasureSpec, int textWidth) { + int oldWidth = button.getMeasuredWidth(); + if (button.getPaddingLeft() != mDoubleLineButtonPaddingHorizontal) { + // Correct for the fact that the button was laid out with single-line horizontal + // padding. + oldWidth += mSingleToDoubleLineButtonWidthIncrease; + } + + // Re-measure the squeezed smart reply button. + button.setPadding(mDoubleLineButtonPaddingHorizontal, button.getPaddingTop(), + mDoubleLineButtonPaddingHorizontal, button.getPaddingBottom()); + final int widthMeasureSpec = MeasureSpec.makeMeasureSpec( + 2 * mDoubleLineButtonPaddingHorizontal + textWidth, MeasureSpec.AT_MOST); + button.measure(widthMeasureSpec, heightMeasureSpec); + + final int newWidth = button.getMeasuredWidth(); + + final LayoutParams lp = (LayoutParams) button.getLayoutParams(); + if (button.getLineCount() > 2 || newWidth >= oldWidth) { + lp.squeezeStatus = LayoutParams.SQUEEZE_STATUS_FAILED; + return SQUEEZE_FAILED; + } else { + lp.squeezeStatus = LayoutParams.SQUEEZE_STATUS_PENDING; + return oldWidth - newWidth; + } + } + + private void updateCornerRadiusAndRemeasureButtonsIfNecessary( + int buttonPaddingHorizontal, int maxChildHeight) { + final float cornerRadius = ((float) maxChildHeight) / 2; + final int maxChildHeightMeasure = + MeasureSpec.makeMeasureSpec(maxChildHeight, MeasureSpec.EXACTLY); + + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (!lp.show) { + continue; + } + + // Update corner radius. + GradientDrawable backgroundDrawable = + (GradientDrawable) ((RippleDrawable) child.getBackground()).getDrawable(0); + backgroundDrawable.setCornerRadius(cornerRadius); + + boolean requiresNewMeasure = false; + int newWidth = child.getMeasuredWidth(); + + // Re-measure reason 1: The button needs to be un-squeezed (either because it resulted + // in more than two lines or because it was unnecessary). + if (lp.squeezeStatus == LayoutParams.SQUEEZE_STATUS_FAILED) { + requiresNewMeasure = true; + newWidth = Integer.MAX_VALUE; + } + + // Re-measure reason 2: The button's horizontal padding is incorrect (because it was + // measured with the wrong number of lines). + if (child.getPaddingLeft() != buttonPaddingHorizontal) { + requiresNewMeasure = true; + if (buttonPaddingHorizontal == mSingleLineButtonPaddingHorizontal) { + // Decrease padding (2->1 line). + newWidth -= mSingleToDoubleLineButtonWidthIncrease; + } else { + // Increase padding (1->2 lines). + newWidth += mSingleToDoubleLineButtonWidthIncrease; + } + child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(), + buttonPaddingHorizontal, child.getPaddingBottom()); + } + + // Re-measure reason 3: The button's height is less than the max height of all buttons + // (all should have the same height). + if (child.getMeasuredHeight() != maxChildHeight) { + requiresNewMeasure = true; + } + + if (requiresNewMeasure) { + child.measure(MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.AT_MOST), + maxChildHeightMeasure); + } + } + } + + private void markButtonsWithPendingSqueezeStatusAs(int squeezeStatus, int maxChildIndex) { + for (int i = 0; i <= maxChildIndex; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (lp.squeezeStatus == LayoutParams.SQUEEZE_STATUS_PENDING) { + lp.squeezeStatus = squeezeStatus; + } + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + final boolean isRtl = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + + final int width = right - left; + int position = isRtl ? width - mPaddingRight : mPaddingLeft; + + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (!lp.show) { + continue; + } + + final int childWidth = child.getMeasuredWidth(); + final int childHeight = child.getMeasuredHeight(); + final int childLeft = isRtl ? position - childWidth : position; + child.layout(childLeft, 0, childLeft + childWidth, childHeight); + + final int childWidthWithSpacing = childWidth + mSpacing; + if (isRtl) { + position -= childWidthWithSpacing; + } else { + position += childWidthWithSpacing; + } + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + return lp.show && super.drawChild(canvas, child, drawingTime); + } + + @VisibleForTesting + static class LayoutParams extends ViewGroup.LayoutParams { + + /** Button is not squeezed. */ + private static final int SQUEEZE_STATUS_NONE = 0; + + /** + * Button was successfully squeezed, but it might be un-squeezed later if the squeezing + * turns out to have been unnecessary (because there's still not enough space to add another + * button). + */ + private static final int SQUEEZE_STATUS_PENDING = 1; + + /** Button was successfully squeezed and it won't be un-squeezed. */ + private static final int SQUEEZE_STATUS_SUCCESSFUL = 2; + + /** + * Button wasn't successfully squeezed. The squeezing resulted in more than two lines of + * text or it didn't reduce the button's width at all. The button will have to be + * re-measured to use only one line of text. + */ + private static final int SQUEEZE_STATUS_FAILED = 3; + + private boolean show = false; + private int squeezeStatus = SQUEEZE_STATUS_NONE; + + private LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + } + + private LayoutParams(int width, int height) { + super(width, height); + } + + @VisibleForTesting + boolean isShown() { + return show; + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java index 0c3637d6e234..58abf19dd238 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java @@ -14,16 +14,27 @@ package com.android.systemui.statusbar.policy; +import static android.view.View.MeasureSpec; + import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; import android.app.PendingIntent; import android.app.RemoteInput; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.LinearLayout; +import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import org.junit.Before; @@ -34,30 +45,40 @@ import org.junit.runner.RunWith; @TestableLooper.RunWithLooper @SmallTest public class SmartReplyViewTest extends SysuiTestCase { - private static final String TEST_RESULT_KEY = "test_result_key"; private static final String TEST_ACTION = "com.android.ACTION"; + private static final String[] TEST_CHOICES = new String[]{"Hello", "What's up?", "I'm here"}; + private static final int WIDTH_SPEC = MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY); + private static final int HEIGHT_SPEC = MeasureSpec.makeMeasureSpec(400, MeasureSpec.AT_MOST); + private BlockingQueueIntentReceiver mReceiver; private SmartReplyView mView; + private int mSingleLinePaddingHorizontal; + private int mDoubleLinePaddingHorizontal; + private int mSpacing; + @Before public void setUp() { mReceiver = new BlockingQueueIntentReceiver(); mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION)); mView = SmartReplyView.inflate(mContext, null); + + + final Resources res = mContext.getResources(); + mSingleLinePaddingHorizontal = res.getDimensionPixelSize( + R.dimen.smart_reply_button_padding_horizontal_single_line); + mDoubleLinePaddingHorizontal = res.getDimensionPixelSize( + R.dimen.smart_reply_button_padding_horizontal_double_line); + mSpacing = res.getDimensionPixelSize(R.dimen.smart_reply_button_spacing); } @Test public void testSendSmartReply_intentContainsResultsAndSource() throws InterruptedException { - PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, - new Intent(TEST_ACTION), 0); - RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).setChoices( - TEST_CHOICES).build(); - - mView.setRepliesFromRemoteInput(input, pendingIntent); + setRepliesFromRemoteInput(TEST_CHOICES); mView.getChildAt(2).performClick(); @@ -66,4 +87,259 @@ public class SmartReplyViewTest extends SysuiTestCase { RemoteInput.getResultsFromIntent(resultIntent).get(TEST_RESULT_KEY)); assertEquals(RemoteInput.SOURCE_CHOICE, RemoteInput.getResultsSource(resultIntent)); } + + @Test + public void testMeasure_empty() { + mView.measure(WIDTH_SPEC, HEIGHT_SPEC); + assertEquals(500, mView.getMeasuredWidthAndState()); + assertEquals(0, mView.getMeasuredHeightAndState()); + } + + @Test + public void testLayout_empty() { + mView.measure(WIDTH_SPEC, HEIGHT_SPEC); + mView.layout(0, 0, 500, 0); + } + + + // Instead of manually calculating the expected measurement/layout results, we build the + // expectations as ordinary linear layouts and then check that the relevant parameters in the + // corresponding SmartReplyView and LinearView are equal. + + @Test + public void testMeasure_shortChoices() { + final CharSequence[] choices = new CharSequence[]{"Hi", "Hello", "Bye"}; + + // All choices should be displayed as SINGLE-line smart reply buttons. + ViewGroup expectedView = buildExpectedView(choices, 1); + expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + + setRepliesFromRemoteInput(choices); + mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + + assertEqualMeasures(expectedView, mView); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0)); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1)); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2)); + } + + @Test + public void testLayout_shortChoices() { + final CharSequence[] choices = new CharSequence[]{"Hi", "Hello", "Bye"}; + + // All choices should be displayed as SINGLE-line smart reply buttons. + ViewGroup expectedView = buildExpectedView(choices, 1); + expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(), + 10 + expectedView.getMeasuredHeight()); + + setRepliesFromRemoteInput(choices); + mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight()); + + assertEqualLayouts(expectedView, mView); + assertEqualLayouts(expectedView.getChildAt(0), mView.getChildAt(0)); + assertEqualLayouts(expectedView.getChildAt(1), mView.getChildAt(1)); + assertEqualLayouts(expectedView.getChildAt(2), mView.getChildAt(2)); + } + + @Test + public void testMeasure_choiceWithTwoLines() { + final CharSequence[] choices = new CharSequence[]{"Hi", "Hello\neveryone", "Bye"}; + + // All choices should be displayed as DOUBLE-line smart reply buttons. + ViewGroup expectedView = buildExpectedView(choices, 2); + expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + + setRepliesFromRemoteInput(choices); + mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + + assertEqualMeasures(expectedView, mView); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0)); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1)); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2)); + } + + @Test + public void testLayout_choiceWithTwoLines() { + final CharSequence[] choices = new CharSequence[]{"Hi", "Hello\neveryone", "Bye"}; + + // All choices should be displayed as DOUBLE-line smart reply buttons. + ViewGroup expectedView = buildExpectedView(choices, 2); + expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(), + 10 + expectedView.getMeasuredHeight()); + + setRepliesFromRemoteInput(choices); + mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight()); + + assertEqualLayouts(expectedView, mView); + assertEqualLayouts(expectedView.getChildAt(0), mView.getChildAt(0)); + assertEqualLayouts(expectedView.getChildAt(1), mView.getChildAt(1)); + assertEqualLayouts(expectedView.getChildAt(2), mView.getChildAt(2)); + } + + @Test + public void testMeasure_choiceWithThreeLines() { + final CharSequence[] choices = new CharSequence[]{"Hi", "Hello\nevery\nbody", "Bye"}; + + // The choice with three lines should NOT be displayed. All other choices should be + // displayed as SINGLE-line smart reply buttons. + ViewGroup expectedView = buildExpectedView(new CharSequence[]{"Hi", "Bye"}, 1); + expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + + setRepliesFromRemoteInput(choices); + mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + + assertEqualMeasures(expectedView, mView); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0)); + assertReplyButtonHidden(mView.getChildAt(1)); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(2)); + } + + @Test + public void testLayout_choiceWithThreeLines() { + final CharSequence[] choices = new CharSequence[]{"Hi", "Hello\nevery\nbody", "Bye"}; + + // The choice with three lines should NOT be displayed. All other choices should be + // displayed as SINGLE-line smart reply buttons. + ViewGroup expectedView = buildExpectedView(new CharSequence[]{"Hi", "Bye"}, 1); + expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(), + 10 + expectedView.getMeasuredHeight()); + + setRepliesFromRemoteInput(choices); + mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight()); + + assertEqualLayouts(expectedView, mView); + assertEqualLayouts(expectedView.getChildAt(0), mView.getChildAt(0)); + // We don't care about mView.getChildAt(1)'s layout because it's hidden (see + // testMeasure_choiceWithThreeLines). + assertEqualLayouts(expectedView.getChildAt(1), mView.getChildAt(2)); + } + + @Test + public void testMeasure_squeezeLongest() { + final CharSequence[] choices = new CharSequence[]{"Short", "Short", "Looooooong replyyyyy"}; + + // All choices should be displayed as DOUBLE-line smart reply buttons. + ViewGroup expectedView = buildExpectedView( + new CharSequence[]{"Short", "Short", "Looooooong \nreplyyyyy"}, 2); + expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + + setRepliesFromRemoteInput(choices); + mView.measure( + MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST), + MeasureSpec.UNSPECIFIED); + + assertEqualMeasures(expectedView, mView); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0)); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1)); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2)); + } + + @Test + public void testLayout_squeezeLongest() { + final CharSequence[] choices = new CharSequence[]{"Short", "Short", "Looooooong replyyyyy"}; + + // All choices should be displayed as DOUBLE-line smart reply buttons. + ViewGroup expectedView = buildExpectedView( + new CharSequence[]{"Short", "Short", "Looooooong \nreplyyyyy"}, 2); + expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(), + 10 + expectedView.getMeasuredHeight()); + + setRepliesFromRemoteInput(choices); + mView.measure( + MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST), + MeasureSpec.UNSPECIFIED); + mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight()); + + assertEqualLayouts(expectedView, mView); + assertEqualLayouts(expectedView.getChildAt(0), mView.getChildAt(0)); + assertEqualLayouts(expectedView.getChildAt(1), mView.getChildAt(1)); + assertEqualLayouts(expectedView.getChildAt(2), mView.getChildAt(2)); + } + + private void setRepliesFromRemoteInput(CharSequence[] choices) { + PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, + new Intent(TEST_ACTION), 0); + RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).setChoices(choices).build(); + mView.setRepliesFromRemoteInput(input, pendingIntent); + } + + /** Builds a {@link ViewGroup} whose measures and layout mirror a {@link SmartReplyView}. */ + private ViewGroup buildExpectedView(CharSequence[] choices, int lineCount) { + LinearLayout layout = new LinearLayout(mContext); + layout.setOrientation(LinearLayout.HORIZONTAL); + + // Baseline alignment causes expected heights to be off by one or two pixels on some + // devices. + layout.setBaselineAligned(false); + + final boolean isRtl = mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + final int paddingHorizontal; + switch (lineCount) { + case 1: + paddingHorizontal = mSingleLinePaddingHorizontal; + break; + case 2: + paddingHorizontal = mDoubleLinePaddingHorizontal; + break; + default: + fail("Invalid line count " + lineCount); + return null; + } + + Button previous = null; + for (CharSequence choice : choices) { + Button current = SmartReplyView.inflateReplyButton(mContext, mView, choice, null, null); + current.setPadding(paddingHorizontal, current.getPaddingTop(), paddingHorizontal, + current.getPaddingBottom()); + if (previous != null) { + ViewGroup.MarginLayoutParams lp = + (ViewGroup.MarginLayoutParams) previous.getLayoutParams(); + if (isRtl) { + lp.leftMargin = mSpacing; + } else { + lp.rightMargin = mSpacing; + } + } + layout.addView(current); + previous = current; + } + + return layout; + } + + private static void assertEqualMeasures(View expected, View actual) { + assertEquals(expected.getMeasuredWidth(), actual.getMeasuredWidth()); + assertEquals(expected.getMeasuredHeight(), actual.getMeasuredHeight()); + } + + private static void assertReplyButtonShownWithEqualMeasures(View expected, View actual) { + assertReplyButtonShown(actual); + assertEqualMeasures(expected, actual); + assertEquals(expected.getPaddingLeft(), actual.getPaddingLeft()); + assertEquals(expected.getPaddingTop(), actual.getPaddingTop()); + assertEquals(expected.getPaddingRight(), actual.getPaddingRight()); + assertEquals(expected.getPaddingBottom(), actual.getPaddingBottom()); + } + + private static void assertReplyButtonShown(View view) { + assertTrue(((SmartReplyView.LayoutParams) view.getLayoutParams()).isShown()); + } + + private static void assertReplyButtonHidden(View view) { + assertFalse(((SmartReplyView.LayoutParams) view.getLayoutParams()).isShown()); + } + + private static void assertEqualLayouts(View expected, View actual) { + assertEquals(expected.getLeft(), actual.getLeft()); + assertEquals(expected.getTop(), actual.getTop()); + assertEquals(expected.getRight(), actual.getRight()); + assertEquals(expected.getBottom(), actual.getBottom()); + } } diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/AndroidManifest.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/AndroidManifest.xml index 71ce6b433215..426aae969fd4 100644 --- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/AndroidManifest.xml +++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/AndroidManifest.xml @@ -2,7 +2,9 @@ package="com.android.internal.display.cutout.emulation.narrow" android:versionCode="1" android:versionName="1.0"> - <overlay android:targetPackage="android" android:priority="1"/> + <overlay android:targetPackage="android" + android:category="com.android.internal.display_cutout_emulation" + android:priority="1"/> <application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/> </manifest> diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/AndroidManifest.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/AndroidManifest.xml index 5a93cfb06c6d..368a2d5c17eb 100644 --- a/packages/overlays/DisplayCutoutEmulationTallOverlay/AndroidManifest.xml +++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/AndroidManifest.xml @@ -18,7 +18,9 @@ package="com.android.internal.display.cutout.emulation.tall" android:versionCode="1" android:versionName="1.0"> - <overlay android:targetPackage="android" android:priority="1"/> + <overlay android:targetPackage="android" + android:category="com.android.internal.display_cutout_emulation" + android:priority="1"/> <application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/> </manifest> diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/AndroidManifest.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/AndroidManifest.xml index 96bd06028611..b721efe8a795 100644 --- a/packages/overlays/DisplayCutoutEmulationWideOverlay/AndroidManifest.xml +++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/AndroidManifest.xml @@ -18,7 +18,9 @@ package="com.android.internal.display.cutout.emulation.wide" android:versionCode="1" android:versionName="1.0"> - <overlay android:targetPackage="android" android:priority="1"/> + <overlay android:targetPackage="android" + android:category="com.android.internal.display_cutout_emulation" + android:priority="1"/> <application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/> </manifest> diff --git a/pathmap.mk b/pathmap.mk index c241d9978316..8b77e62860b8 100644 --- a/pathmap.mk +++ b/pathmap.mk @@ -20,11 +20,6 @@ # directories, despite the fact that it was historically used for that! # -# Import path mappings from the support library project. This will set up -# FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS and FRAMEWORKS_SUPPORT_JAVA_LIBRARIES for -# use later in this file. -include $(LOCAL_PATH)/../support/pathmap.mk - # # A list of all source roots under frameworks/multidex. # diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index abf1de578682..e118c4999712 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -3985,6 +3985,8 @@ message MetricsEvent { // Package: Package of app that was autofilled // Tag FIELD_AUTOFILL_FILTERTEXT_LEN: The length of the filter text // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets shown + // NOTE: starting on OS P, it also added the following field: + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request AUTOFILL_FILL_UI = 910; // Tag of a field for the length of the filter text @@ -4011,7 +4013,9 @@ message MetricsEvent { // Type TYPE_CLOSE: UI was destroyed without influence of the user // Type TYPE_ACTION: data was saved // Package: Package of app that was autofilled - // Tag FIELD_AUTOFILL_NUM_ID: The number of ids that are saved + // Tag FIELD_AUTOFILL_NUM_IDS: The number of ids that are saved + // NOTE: starting on OS P, it also added the following field: + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request AUTOFILL_SAVE_UI = 916; // Tag of a field for the number of saveable ids @@ -5083,7 +5087,8 @@ message MetricsEvent { // An autofill service updated its user data // Package: Package of the autofill service that updated the user data - // Counter: number of fields added (or 0 if reset) + // Tag FIELD_AUTOFILL_NUM_VALUES: number of fields added (or 0 if reset) + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request // OS: P AUTOFILL_USERDATA_UPDATED = 1272; @@ -5171,7 +5176,6 @@ message MetricsEvent { // An autofill service was bound using an unofficial(but still supported) permission. // Package: Package of the autofill service // OS: P - AUTOFILL_INVALID_PERMISSION = 1289; // OPEN: QS Alarm tile shown diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 3689536b6ed8..1ae61af59d84 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -327,11 +327,7 @@ public final class AutofillManagerService extends SystemService { mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi, mDisabledUsers.get(resolvedUserId)); mServicesCache.put(userId, service); - final ArrayMap<String, Pair<Long, String>> compatPackages = - service.getCompatibilityPackagesLocked(); - if (compatPackages != null) { - addCompatibilityModeRequests(compatPackages, userId); - } + addCompatibilityModeRequestsLocked(service, userId); } return service; } @@ -521,24 +517,23 @@ public final class AutofillManagerService extends SystemService { if (!service.isEnabledLocked()) { removeCachedServiceLocked(userId); } else { - final ArrayMap<String, Pair<Long, String>> compatPackages = - service.getCompatibilityPackagesLocked(); - if (compatPackages != null) { - addCompatibilityModeRequests(compatPackages, userId); - } + addCompatibilityModeRequestsLocked(service, userId); } } } - private void addCompatibilityModeRequests( - @NonNull ArrayMap<String, Pair<Long, String>> compatPackages, int userId) { - final Set<String> whiteListedPackages = Build.IS_ENG ? null - : getWhitelistedCompatModePackages(); + private void addCompatibilityModeRequestsLocked(@NonNull AutofillManagerServiceImpl service + , int userId) { + final ArrayMap<String, Pair<Long, String>> compatPackages = + service.getCompatibilityPackagesLocked(); + if (compatPackages == null || compatPackages.isEmpty()) { + return; + } + final Set<String> whiteListedPackages = getWhitelistedCompatModePackages(); final int compatPackageCount = compatPackages.size(); for (int i = 0; i < compatPackageCount; i++) { final String packageName = compatPackages.keyAt(i); - if (!Build.IS_ENG && (whiteListedPackages == null - || !whiteListedPackages.contains(packageName))) { + if (whiteListedPackages == null || !whiteListedPackages.contains(packageName)) { Slog.w(TAG, "Ignoring not whitelisted compat package " + packageName); continue; } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 712ea36be6ca..eab4d119e7d2 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -873,7 +873,7 @@ final class AutofillManagerServiceImpl { int numberFields = mUserData == null ? 0: mUserData.getCategoryIds().length; mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED, getServicePackageName(), null) - .setCounterValue(numberFields)); + .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, numberFields)); } } diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index a422b7ccd274..9cd3621eb737 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -16,6 +16,13 @@ package com.android.server; +import static android.app.AlarmManager.ELAPSED_REALTIME; +import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP; +import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE; +import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED; +import static android.app.AlarmManager.RTC; +import static android.app.AlarmManager.RTC_WAKEUP; + import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; @@ -46,6 +53,7 @@ import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Message; +import android.os.ParcelableException; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; @@ -62,6 +70,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.KeyValueListParser; import android.util.Log; +import android.util.NtpTrustedTime; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -70,10 +79,18 @@ import android.util.SparseLongArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.DumpUtils; +import com.android.internal.util.LocalLog; +import com.android.server.AppStateTracker.Listener; + import java.io.ByteArrayOutputStream; import java.io.FileDescriptor; import java.io.PrintWriter; import java.text.SimpleDateFormat; +import java.time.DateTimeException; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -88,21 +105,6 @@ import java.util.TimeZone; import java.util.TreeSet; import java.util.function.Predicate; -import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE; -import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED; -import static android.app.AlarmManager.RTC_WAKEUP; -import static android.app.AlarmManager.RTC; -import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP; -import static android.app.AlarmManager.ELAPSED_REALTIME; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.DumpUtils; -import com.android.internal.util.LocalLog; -import com.android.internal.util.Preconditions; -import com.android.server.AppStateTracker.Listener; - /** * Alarm manager implementaion. * @@ -1794,6 +1796,16 @@ class AlarmManagerService extends SystemService { } @Override + public long currentNetworkTimeMillis() { + final NtpTrustedTime time = NtpTrustedTime.getInstance(getContext()); + if (time.hasCache()) { + return time.currentTimeMillis(); + } else { + throw new ParcelableException(new DateTimeException("Missing NTP fix")); + } + } + + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return; diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java index 2c24798204eb..b3a8fb61506b 100644 --- a/services/core/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java @@ -23,7 +23,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.PackageManager; import android.database.ContentObserver; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; @@ -33,13 +32,12 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; -import android.os.SystemClock; import android.os.PowerManager; +import android.os.SystemClock; import android.provider.Settings; import android.util.Log; import android.util.NtpTrustedTime; import android.util.TimeUtils; -import android.util.TrustedTime; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.DumpUtils; @@ -75,19 +73,17 @@ public class NetworkTimeUpdateService extends Binder { private long mNitzTimeSetTime = NOT_SET; private Network mDefaultNetwork = null; - private Context mContext; - private TrustedTime mTime; + private final Context mContext; + private final NtpTrustedTime mTime; + private final AlarmManager mAlarmManager; + private final ConnectivityManager mCM; + private final PendingIntent mPendingPollIntent; + private final PowerManager.WakeLock mWakeLock; // NTP lookup is done on this thread and handler private Handler mHandler; - private AlarmManager mAlarmManager; - private PendingIntent mPendingPollIntent; private SettingsObserver mSettingsObserver; - private ConnectivityManager mCM; private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback; - // The last time that we successfully fetched the NTP time. - private long mLastNtpFetchTime = NOT_SET; - private final PowerManager.WakeLock mWakeLock; // Normal polling frequency private final long mPollingIntervalMs; @@ -105,8 +101,9 @@ public class NetworkTimeUpdateService extends Binder { public NetworkTimeUpdateService(Context context) { mContext = context; mTime = NtpTrustedTime.getInstance(context); - mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); - mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + mAlarmManager = mContext.getSystemService(AlarmManager.class); + mCM = mContext.getSystemService(ConnectivityManager.class); + Intent pollIntent = new Intent(ACTION_POLL, null); mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0); @@ -119,7 +116,7 @@ public class NetworkTimeUpdateService extends Binder { mTimeErrorThresholdMs = mContext.getResources().getInteger( com.android.internal.R.integer.config_ntpThreshold); - mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock( + mWakeLock = context.getSystemService(PowerManager.class).newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, TAG); } @@ -157,7 +154,7 @@ public class NetworkTimeUpdateService extends Binder { private void onPollNetworkTime(int event) { // If Automatic time is not set, don't bother. Similarly, if we don't // have any default network, don't bother. - if (!isAutomaticTimeRequested() || mDefaultNetwork == null) return; + if (mDefaultNetwork == null) return; mWakeLock.acquire(); try { onPollNetworkTimeUnderWakeLock(event); @@ -167,61 +164,60 @@ public class NetworkTimeUpdateService extends Binder { } private void onPollNetworkTimeUnderWakeLock(int event) { - final long refTime = SystemClock.elapsedRealtime(); - // If NITZ time was received less than mPollingIntervalMs time ago, - // no need to sync to NTP. - if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) { - resetAlarm(mPollingIntervalMs); - return; + // Force an NTP fix when outdated + if (mTime.getCacheAge() >= mPollingIntervalMs) { + if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh"); + mTime.forceRefresh(); } - final long currentTime = System.currentTimeMillis(); - if (DBG) Log.d(TAG, "System time = " + currentTime); - // Get the NTP time - if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs - || event == EVENT_AUTO_TIME_CHANGED) { - if (DBG) Log.d(TAG, "Before Ntp fetch"); - - // force refresh NTP cache when outdated - if (mTime.getCacheAge() >= mPollingIntervalMs) { - mTime.forceRefresh(); + + if (mTime.getCacheAge() < mPollingIntervalMs) { + // Obtained fresh fix; schedule next normal update + resetAlarm(mPollingIntervalMs); + if (isAutomaticTimeRequested()) { + updateSystemClock(event); } - // only update when NTP time is fresh - if (mTime.getCacheAge() < mPollingIntervalMs) { - final long ntp = mTime.currentTimeMillis(); - mTryAgainCounter = 0; - // If the clock is more than N seconds off or this is the first time it's been - // fetched since boot, set the current time. - if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs - || mLastNtpFetchTime == NOT_SET) { - // Set the system time - if (DBG && mLastNtpFetchTime == NOT_SET - && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) { - Log.d(TAG, "For initial setup, rtc = " + currentTime); - } - if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp); - // Make sure we don't overflow, since it's going to be converted to an int - if (ntp / 1000 < Integer.MAX_VALUE) { - SystemClock.setCurrentTimeMillis(ntp); - } - } else { - if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp); - } - mLastNtpFetchTime = SystemClock.elapsedRealtime(); + } else { + // No fresh fix; schedule retry + mTryAgainCounter++; + if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) { + resetAlarm(mPollingIntervalShorterMs); } else { - // Try again shortly - mTryAgainCounter++; - if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) { - resetAlarm(mPollingIntervalShorterMs); - } else { - // Try much later - mTryAgainCounter = 0; - resetAlarm(mPollingIntervalMs); - } + // Try much later + mTryAgainCounter = 0; + resetAlarm(mPollingIntervalMs); + } + } + } + + private long getNitzAge() { + if (mNitzTimeSetTime == NOT_SET) { + return Long.MAX_VALUE; + } else { + return SystemClock.elapsedRealtime() - mNitzTimeSetTime; + } + } + + /** + * Consider updating system clock based on current NTP fix, if requested by + * user, significant enough delta, and we don't have a recent NITZ. + */ + private void updateSystemClock(int event) { + final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED); + if (!forceUpdate) { + if (getNitzAge() < mPollingIntervalMs) { + if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ"); + return; + } + + final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis()); + if (skew < mTimeErrorThresholdMs) { + if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew"); return; } } - resetAlarm(mPollingIntervalMs); + + SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis()); } /** @@ -326,8 +322,8 @@ public class NetworkTimeUpdateService extends Binder { pw.print("TimeErrorThresholdMs: "); TimeUtils.formatDuration(mTimeErrorThresholdMs, pw); pw.println("\nTryAgainCounter: " + mTryAgainCounter); - pw.print("LastNtpFetchTime: "); - TimeUtils.formatDuration(mLastNtpFetchTime, pw); + pw.println("NTP cache age: " + mTime.getCacheAge()); + pw.println("NTP cache certainty: " + mTime.getCacheCertainty()); pw.println(); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5f8a5abf9564..2af284c12288 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -192,6 +192,7 @@ import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; +import static com.android.server.am.MemoryStatUtil.readMemoryStatFromMemcg; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; @@ -248,6 +249,7 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.PictureInPictureParams; +import android.app.ProcessMemoryState; import android.app.ProfilerInfo; import android.app.RemoteAction; import android.app.WaitResult; @@ -436,6 +438,7 @@ import com.android.server.SystemServiceManager; import com.android.server.ThreadPriorityBooster; import com.android.server.Watchdog; import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.am.MemoryStatUtil.MemoryStat; import com.android.server.am.proto.ActivityManagerServiceProto; import com.android.server.am.proto.BroadcastProto; import com.android.server.am.proto.GrantUriProto; @@ -608,6 +611,9 @@ public class ActivityManagerService extends IActivityManager.Stub // as one line, but close enough for now. static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100; + /** If a UID observer takes more than this long, send a WTF. */ + private static final int SLOW_UID_OBSERVER_THRESHOLD_MS = 20; + // Access modes for handleIncomingUser. static final int ALLOW_NON_FULL = 0; static final int ALLOW_NON_FULL_IN_PROFILE = 1; @@ -780,6 +786,9 @@ public class ActivityManagerService extends IActivityManager.Stub @VisibleForTesting long mWaitForNetworkTimeoutMs; + /** Total # of UID change events dispatched, shown in dumpsys. */ + int mUidChangeDispatchCount; + /** * Helper class which strips out priority and proto arguments then calls the dump function with * the appropriate arguments. If priority arguments are omitted, function calls the legacy @@ -1702,6 +1711,15 @@ public class ActivityManagerService extends IActivityManager.Stub final int which; final int cutpoint; + /** + * Total # of callback calls that took more than {@link #SLOW_UID_OBSERVER_THRESHOLD_MS}. + * We show it in dumpsys. + */ + int mSlowDispatchCount; + + /** Max time it took for each dispatch. */ + int mMaxDispatchTime; + final SparseIntArray lastProcStates; // Please keep the enum lists in sync @@ -4721,6 +4739,7 @@ public class ActivityManagerService extends IActivityManager.Stub "*** Delivering " + N + " uid changes"); } + mUidChangeDispatchCount += N; int i = mUidObservers.beginBroadcast(); while (i > 0) { i--; @@ -4773,6 +4792,7 @@ public class ActivityManagerService extends IActivityManager.Stub // interested in all proc state changes. continue; } + final long start = SystemClock.uptimeMillis(); if ((change & UidRecord.CHANGE_IDLE) != 0) { if ((reg.which & ActivityManager.UID_OBSERVER_IDLE) != 0) { if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, @@ -4833,6 +4853,13 @@ public class ActivityManagerService extends IActivityManager.Stub } } } + final int duration = (int) (SystemClock.uptimeMillis() - start); + if (reg.mMaxDispatchTime < duration) { + reg.mMaxDispatchTime = duration; + } + if (duration >= SLOW_UID_OBSERVER_THRESHOLD_MS) { + reg.mSlowDispatchCount++; + } } } catch (RemoteException e) { } @@ -16793,6 +16820,25 @@ public class ActivityManagerService extends IActivityManager.Stub pw.print(" mLowRamSinceLastIdle="); TimeUtils.formatDuration(getLowRamTimeSinceIdle(now), pw); pw.println(); + pw.println(); + pw.print(" mUidChangeDispatchCount="); + pw.print(mUidChangeDispatchCount); + pw.println(); + + pw.println(" Slow UID dispatches:"); + final int N = mUidObservers.beginBroadcast(); + for (int i = 0; i < N; i++) { + UidObserverRegistration r = + (UidObserverRegistration) mUidObservers.getBroadcastCookie(i); + pw.print(" "); + pw.print(mUidObservers.getBroadcastItem(i).getClass().getTypeName()); + pw.print(": "); + pw.print(r.mSlowDispatchCount); + pw.print(" / Max "); + pw.print(r.mMaxDispatchTime); + pw.println("ms"); + } + mUidObservers.finishBroadcast(); } } pw.println(" mForceBackgroundCheck=" + mForceBackgroundCheck); @@ -26097,6 +26143,33 @@ public class ActivityManagerService extends IActivityManager.Stub return (uidRec != null) && !uidRec.idle; } } + + @Override + public List<ProcessMemoryState> getMemoryStateForProcesses() { + List<ProcessMemoryState> processMemoryStates = new ArrayList<>(); + synchronized (mPidsSelfLocked) { + for (int i = 0, size = mPidsSelfLocked.size(); i < size; i++) { + final ProcessRecord r = mPidsSelfLocked.valueAt(i); + final int pid = r.pid; + final int uid = r.uid; + final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid); + if (memoryStat == null) { + continue; + } + ProcessMemoryState processMemoryState = + new ProcessMemoryState(uid, + r.processName, + r.maxAdj, + memoryStat.pgfault, + memoryStat.pgmajfault, + memoryStat.rssInBytes, + memoryStat.cacheInBytes, + memoryStat.swapInBytes); + processMemoryStates.add(processMemoryState); + } + } + return processMemoryStates; + } } /** diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index fba03774e5d9..1f101814d294 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -139,7 +139,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } @Override - public Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff) { + public Future<?> scheduleReadProcStateCpuTimes( + boolean onBattery, boolean onBatteryScreenOff, long delayMillis) { synchronized (mStats) { if (!mStats.trackPerProcStateCpuTimes()) { return null; @@ -147,9 +148,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } synchronized (BatteryExternalStatsWorker.this) { if (!mExecutorService.isShutdown()) { - return mExecutorService.submit(PooledLambda.obtainRunnable( + return mExecutorService.schedule(PooledLambda.obtainRunnable( BatteryStatsImpl::updateProcStateCpuTimes, - mStats, onBattery, onBatteryScreenOff).recycleOnUse()); + mStats, onBattery, onBatteryScreenOff).recycleOnUse(), + delayMillis, TimeUnit.MILLISECONDS); } } return null; diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java index d97c2a24ef1e..a2a84ec43ed2 100644 --- a/services/core/java/com/android/server/am/MemoryStatUtil.java +++ b/services/core/java/com/android/server/am/MemoryStatUtil.java @@ -28,7 +28,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.File; import java.io.IOException; -import java.util.ArrayList; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -52,8 +52,9 @@ final class MemoryStatUtil { /** * Reads memory.stat of a process from memcg. */ - static @Nullable MemoryStat readMemoryStatFromMemcg(int uid, int pid) { - final String memoryStatPath = String.format(MEMORY_STAT_FILE_FMT, uid, pid); + @Nullable + static MemoryStat readMemoryStatFromMemcg(int uid, int pid) { + final String memoryStatPath = String.format(Locale.US, MEMORY_STAT_FILE_FMT, uid, pid); final File memoryStatFile = new File(memoryStatPath); if (!memoryStatFile.exists()) { if (DEBUG_METRICS) Slog.i(TAG, memoryStatPath + " not found"); @@ -74,7 +75,8 @@ final class MemoryStatUtil { * Parses relevant statistics out from the contents of a memory.stat file in memcg. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - static @Nullable MemoryStat parseMemoryStat(String memoryStatContents) { + @Nullable + static MemoryStat parseMemoryStat(String memoryStatContents) { MemoryStat memoryStat = new MemoryStat(); if (memoryStatContents == null) { return memoryStat; diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 95a024698864..63308f894d09 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -300,7 +300,7 @@ public final class ContentService extends IContentService.Stub { void onBootPhase(int phase) { switch (phase) { - case SystemService.PHASE_SYSTEM_SERVICES_READY: + case SystemService.PHASE_ACTIVITY_MANAGER_READY: getSyncManager(); break; } diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 79450a0f85b5..70892685d8b4 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -747,9 +747,9 @@ public class SyncManager { } public void onBootPhase(int phase) { - // Note SyncManager only receives PHASE_SYSTEM_SERVICES_READY and after. + // Note SyncManager only receives PHASE_ACTIVITY_MANAGER_READY and after. switch (phase) { - case SystemService.PHASE_SYSTEM_SERVICES_READY: + case SystemService.PHASE_ACTIVITY_MANAGER_READY: mConstants.start(); break; } diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 3e43d8ed918d..9d2a8e28a3a0 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -16,6 +16,7 @@ package com.android.server.location; +import android.annotation.Nullable; import android.app.AlarmManager; import android.app.AppOpsManager; import android.app.PendingIntent; @@ -28,11 +29,11 @@ import android.hardware.location.GeofenceHardware; import android.hardware.location.GeofenceHardwareImpl; import android.location.Criteria; import android.location.FusedBatchOptions; +import android.location.GnssMeasurementsEvent; +import android.location.GnssNavigationMessage; import android.location.GnssStatus; import android.location.IGnssStatusListener; import android.location.IGnssStatusProvider; -import android.location.GnssMeasurementsEvent; -import android.location.GnssNavigationMessage; import android.location.IGpsGeofenceHardware; import android.location.ILocationManager; import android.location.INetInitiatedListener; @@ -48,16 +49,16 @@ import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.Uri; import android.os.AsyncTask; -import android.os.PowerManager.ServiceType; -import android.os.PowerSaveState; import android.os.BatteryStats; import android.os.Binder; import android.os.Bundle; -import android.os.PersistableBundle; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.PersistableBundle; import android.os.PowerManager; +import android.os.PowerManager.ServiceType; +import android.os.PowerSaveState; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -68,25 +69,21 @@ import android.os.WorkSource.WorkChain; import android.provider.Settings; import android.provider.Telephony.Carriers; import android.provider.Telephony.Sms.Intents; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; -import android.telephony.CarrierConfigManager; import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; import android.util.Log; import android.util.NtpTrustedTime; - import com.android.internal.app.IAppOpsService; import com.android.internal.app.IBatteryStats; -import com.android.internal.location.gnssmetrics.GnssMetrics; import com.android.internal.location.GpsNetInitiatedHandler; import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; - -import libcore.io.IoUtils; - +import com.android.internal.location.gnssmetrics.GnssMetrics; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -97,11 +94,13 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Properties; -import java.util.Map; -import java.util.HashMap; + +import libcore.io.IoUtils; /** * A GNSS implementation of LocationProvider used by LocationManager. @@ -215,6 +214,7 @@ public class GnssLocationProvider implements LocationProviderInterface { private static final int INITIALIZE_HANDLER = 13; private static final int REQUEST_SUPL_CONNECTION = 14; private static final int RELEASE_SUPL_CONNECTION = 15; + private static final int REQUEST_LOCATION = 16; // Request setid private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1; @@ -248,6 +248,13 @@ public class GnssLocationProvider implements LocationProviderInterface { private static final int TCP_MIN_PORT = 0; private static final int TCP_MAX_PORT = 0xffff; + // 10 seconds. + private static final long LOCATION_TIME_FRESHNESS_THESHOLD_MILLIS = 10 * 1000; + // 1 second, or 1 Hz frequency. + private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000; + // 30 seconds. + private static final long LOCATION_UPDATE_DURATION_MILLIS = 30 * 1000; + /** simpler wrapper for ProviderRequest + Worksource */ private static class GpsRequest { public ProviderRequest request; @@ -409,6 +416,8 @@ public class GnssLocationProvider implements LocationProviderInterface { private final GnssStatusListenerHelper mListenerHelper; private final GnssMeasurementsProvider mGnssMeasurementsProvider; private final GnssNavigationMessageProvider mGnssNavigationMessageProvider; + private final FusedLocationListener mFusedLocationListener = new FusedLocationListener(); + private static int sNumFusedLocationUpdatesRequests = 0; // Handler for processing events private Handler mHandler; @@ -1074,6 +1083,89 @@ public class GnssLocationProvider implements LocationProviderInterface { }); } + private void handleRequestLocation(boolean independentFromGnss) { + if (isRequestLocationRateLimited()) { + if (DEBUG) { + Log.d(TAG, "RequestLocation is denied due to too frequent requests."); + } + return; + } + + LocationManager locationManager = (LocationManager) mContext.getSystemService( + Context.LOCATION_SERVICE); + + if (independentFromGnss) { + // For fast GNSS TTFF + Location networkLocation = getLastFreshLocation(locationManager, + LocationManager.NETWORK_PROVIDER); + if (networkLocation != null) { + handleUpdateLocation(networkLocation); + return; + } + locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, + new NetworkLocationListener(), + mHandler.getLooper()); + } else { + // For Device-Based Hybrid (E911) + locationManager.requestLocationUpdates(LocationManager.FUSED_PROVIDER, + LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0, + mFusedLocationListener, mHandler.getLooper()); + sNumFusedLocationUpdatesRequests++; + mHandler.postDelayed(() -> { + if (--sNumFusedLocationUpdatesRequests == 0) { + locationManager.removeUpdates(mFusedLocationListener); + } + }, LOCATION_UPDATE_DURATION_MILLIS); + } + } + + private void injectBestLocation(Location location) { + int gnssLocationFlags = LOCATION_HAS_LAT_LONG | + (location.hasAltitude() ? LOCATION_HAS_ALTITUDE : 0) | + (location.hasSpeed() ? LOCATION_HAS_SPEED : 0) | + (location.hasBearing() ? LOCATION_HAS_BEARING : 0) | + (location.hasAccuracy() ? LOCATION_HAS_HORIZONTAL_ACCURACY : 0) | + (location.hasVerticalAccuracy() ? LOCATION_HAS_VERTICAL_ACCURACY : 0) | + (location.hasSpeedAccuracy() ? LOCATION_HAS_SPEED_ACCURACY : 0) | + (location.hasBearingAccuracy() ? LOCATION_HAS_BEARING_ACCURACY : 0); + + double latitudeDegrees = location.getLatitude(); + double longitudeDegrees = location.getLongitude(); + double altitudeMeters = location.getAltitude(); + float speedMetersPerSec = location.getSpeed(); + float bearingDegrees = location.getBearing(); + float horizontalAccuracyMeters = location.getAccuracy(); + float verticalAccuracyMeters = location.getVerticalAccuracyMeters(); + float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond(); + float bearingAccuracyDegrees = location.getBearingAccuracyDegrees(); + long timestamp = location.getTime(); + native_inject_best_location(gnssLocationFlags, latitudeDegrees, longitudeDegrees, + altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters, + verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees, + timestamp); + } + + /** + * Get the last fresh location. + * + * Return null if the last location is not available or not fresh. + */ + private @Nullable + Location getLastFreshLocation(LocationManager locationManager, String provider) { + Location location = locationManager.getLastKnownLocation(provider); + if (location != null && System.currentTimeMillis() - location.getTime() + < LOCATION_TIME_FRESHNESS_THESHOLD_MILLIS) { + return location; + } + return null; + } + + /** Returns true if the location request is too frequent. */ + private boolean isRequestLocationRateLimited() { + // TODO(b/73198123): implement exponential backoff. + return false; + } + private void handleDownloadXtraData() { if (!mSupportsXtra) { // native code reports xtra not supported, don't try @@ -2271,6 +2363,16 @@ public class GnssLocationProvider implements LocationProviderInterface { } /** + * Called from native code to request location info. + */ + private void requestLocation(boolean independentFromGnss) { + if (DEBUG) { + Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss); + } + sendMessage(REQUEST_LOCATION, 0, independentFromGnss); + } + + /** * Called from native code to request utc time info */ private void requestUtcTime() { @@ -2281,7 +2383,6 @@ public class GnssLocationProvider implements LocationProviderInterface { /** * Called from native code to request reference location info */ - private void requestRefLocation() { TelephonyManager phone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); @@ -2357,6 +2458,9 @@ public class GnssLocationProvider implements LocationProviderInterface { case INJECT_NTP_TIME: handleInjectNtpTime(); break; + case REQUEST_LOCATION: + handleRequestLocation((boolean) msg.obj); + break; case DOWNLOAD_XTRA_DATA: handleDownloadXtraData(); break; @@ -2482,15 +2586,7 @@ public class GnssLocationProvider implements LocationProviderInterface { } } - private final class NetworkLocationListener implements LocationListener { - @Override - public void onLocationChanged(Location location) { - // this callback happens on mHandler looper - if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { - handleUpdateLocation(location); - } - } - + private abstract class LocationChangeListener implements LocationListener { @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @@ -2504,6 +2600,26 @@ public class GnssLocationProvider implements LocationProviderInterface { } } + private final class NetworkLocationListener extends LocationChangeListener { + @Override + public void onLocationChanged(Location location) { + // this callback happens on mHandler looper + if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { + handleUpdateLocation(location); + } + } + } + + private final class FusedLocationListener extends LocationChangeListener { + @Override + public void onLocationChanged(Location location) { + if (LocationManager.FUSED_PROVIDER.equals(location.getProvider())) { + Log.d(TAG, "fused location listener: " + location); + injectBestLocation(location); + } + } + } + private String getSelectedApn() { Uri uri = Uri.parse("content://telephony/carriers/preferapn"); Cursor cursor = null; @@ -2668,6 +2784,8 @@ public class GnssLocationProvider implements LocationProviderInterface { return "RELEASE_SUPL_CONNECTION"; case INJECT_NTP_TIME: return "INJECT_NTP_TIME"; + case REQUEST_LOCATION: + return "REQUEST_LOCATION"; case DOWNLOAD_XTRA_DATA: return "DOWNLOAD_XTRA_DATA"; case INJECT_NTP_TIME_FINISHED: @@ -2788,6 +2906,19 @@ public class GnssLocationProvider implements LocationProviderInterface { private native int native_read_nmea(byte[] buffer, int bufferSize); + private native void native_inject_best_location( + int gnssLocationFlags, + double latitudeDegrees, + double longitudeDegrees, + double altitudeMeters, + float speedMetersPerSec, + float bearingDegrees, + float horizontalAccuracyMeters, + float verticalAccuracyMeters, + float speedAccuracyMetersPerSecond, + float bearingAccuracyDegrees, + long timestamp); + private native void native_inject_location(double latitude, double longitude, float accuracy); // XTRA Support diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index e2b2d46eb4a6..bd9ec55abc04 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -147,6 +147,7 @@ import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Build; import android.os.Environment; +import android.os.BestClock; import android.os.Handler; import android.os.HandlerThread; import android.os.IDeviceIdleController; @@ -164,6 +165,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.ShellCallback; +import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; @@ -183,7 +185,6 @@ import android.util.ArraySet; import android.util.AtomicFile; import android.util.DataUnit; import android.util.Log; -import android.util.NtpTrustedTime; import android.util.Pair; import android.util.RecurrenceRule; import android.util.Slog; @@ -191,7 +192,6 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.SparseLongArray; -import android.util.TrustedTime; import android.util.Xml; import com.android.internal.R; @@ -226,7 +226,9 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; +import java.time.Clock; import java.time.ZoneId; +import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Calendar; @@ -335,8 +337,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final String ACTION_SNOOZE_RAPID = "com.android.server.net.action.SNOOZE_RAPID"; - private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS; - /** * Indicates the maximum wait time for admin data to be available; */ @@ -362,7 +362,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private final INetworkStatsService mNetworkStats; private final INetworkManagementService mNetworkManager; private UsageStatsManagerInternal mUsageStats; - private final TrustedTime mTime; + private final Clock mClock; private final UserManager mUserManager; private final CarrierConfigManager mCarrierConfigManager; @@ -518,24 +518,29 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { public NetworkPolicyManagerService(Context context, IActivityManager activityManager, INetworkStatsService networkStats, INetworkManagementService networkManagement) { this(context, activityManager, networkStats, networkManagement, - AppGlobals.getPackageManager(), NtpTrustedTime.getInstance(context), getSystemDir(), + AppGlobals.getPackageManager(), getDefaultClock(), getDefaultSystemDir(), false); } - private static File getSystemDir() { + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } + private static @NonNull Clock getDefaultClock() { + return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(), + Clock.systemUTC()); + } + public NetworkPolicyManagerService(Context context, IActivityManager activityManager, INetworkStatsService networkStats, INetworkManagementService networkManagement, - IPackageManager pm, TrustedTime time, File systemDir, boolean suppressDefaultPolicy) { + IPackageManager pm, Clock clock, File systemDir, boolean suppressDefaultPolicy) { mContext = checkNotNull(context, "missing context"); mActivityManager = checkNotNull(activityManager, "missing activityManager"); mNetworkStats = checkNotNull(networkStats, "missing networkStats"); mNetworkManager = checkNotNull(networkManagement, "missing networkManagement"); mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService( Context.DEVICE_IDLE_CONTROLLER)); - mTime = checkNotNull(time, "missing TrustedTime"); + mClock = checkNotNull(clock, "missing Clock"); mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); mIPm = pm; @@ -932,7 +937,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // on background handler thread, and verified // READ_NETWORK_USAGE_HISTORY permission above. - maybeRefreshTrustedTime(); synchronized (mNetworkPoliciesSecondLock) { updateNetworkEnabledNL(); updateNotificationsNL(); @@ -1042,7 +1046,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // cycle boundary to recompute notifications. // examine stats for each active policy - final long now = currentTimeMillis(); + final long now = mClock.millis(); for (int i = mNetworkPolicy.size()-1; i >= 0; i--) { final NetworkPolicy policy = mNetworkPolicy.valueAt(i); // ignore policies that aren't relevant to user @@ -1299,7 +1303,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // on background handler thread, and verified CONNECTIVITY_INTERNAL // permission above. - maybeRefreshTrustedTime(); synchronized (mUidRulesFirstLock) { synchronized (mNetworkPoliciesSecondLock) { ensureActiveMobilePolicyAL(); @@ -1462,7 +1465,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final TelephonyManager tele = mContext.getSystemService(TelephonyManager.class); final String subscriberId = tele.getSubscriberId(subId); - maybeRefreshTrustedTime(); synchronized (mUidRulesFirstLock) { synchronized (mNetworkPoliciesSecondLock) { final boolean added = ensureActiveMobilePolicyAL(subId, subscriberId); @@ -1723,7 +1725,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final long totalBytes = getTotalBytes( NetworkTemplate.buildTemplateMobileAll(state.subscriberId), start, end); final long remainingBytes = limitBytes - totalBytes; - final long remainingDays = Math.max(1, (end - currentTimeMillis()) + final long remainingDays = Math.max(1, (end - mClock.millis()) / TimeUnit.DAYS.toMillis(1)); if (remainingBytes > 0) { quotaBytes = (remainingBytes / remainingDays) / 10; @@ -2444,7 +2446,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final long token = Binder.clearCallingIdentity(); try { - maybeRefreshTrustedTime(); synchronized (mUidRulesFirstLock) { synchronized (mNetworkPoliciesSecondLock) { normalizePoliciesNL(policies); @@ -2524,8 +2525,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } void performSnooze(NetworkTemplate template, int type) { - maybeRefreshTrustedTime(); - final long currentTime = currentTimeMillis(); + final long currentTime = mClock.millis(); synchronized (mUidRulesFirstLock) { synchronized (mNetworkPoliciesSecondLock) { // find and snooze local policy that matches @@ -2571,7 +2571,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); final long token = Binder.clearCallingIdentity(); try { - maybeRefreshTrustedTime(); synchronized (mUidRulesFirstLock) { setRestrictBackgroundUL(restrictBackground); } @@ -2916,7 +2915,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final long token = Binder.clearCallingIdentity(); try { - maybeRefreshTrustedTime(); synchronized (mUidRulesFirstLock) { synchronized (mNetworkPoliciesSecondLock) { mSubscriptionPlans.put(subId, plans); @@ -4028,7 +4026,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { case MSG_LIMIT_REACHED: { final String iface = (String) msg.obj; - maybeRefreshTrustedTime(); synchronized (mNetworkPoliciesSecondLock) { if (mMeteredIfaces.contains(iface)) { try { @@ -4393,19 +4390,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - /** - * Try refreshing {@link #mTime} when stale. - */ - void maybeRefreshTrustedTime() { - if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) { - mTime.forceRefresh(); - } - } - - private long currentTimeMillis() { - return mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - } - private static Intent buildAllowBackgroundDataIntent() { return new Intent(ACTION_ALLOW_BACKGROUND); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 76c4db134036..d1aa21276bb0 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -68,6 +68,7 @@ import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; +import android.annotation.NonNull; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.usage.NetworkStatsManager; @@ -97,6 +98,7 @@ import android.net.TrafficStats; import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; +import android.os.BestClock; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -120,10 +122,8 @@ import android.util.ArraySet; import android.util.EventLog; import android.util.Log; import android.util.MathUtils; -import android.util.NtpTrustedTime; import android.util.Slog; import android.util.SparseIntArray; -import android.util.TrustedTime; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; @@ -140,6 +140,8 @@ import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; +import java.time.Clock; +import java.time.ZoneOffset; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -167,7 +169,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final Context mContext; private final INetworkManagementService mNetworkManager; private final AlarmManager mAlarmManager; - private final TrustedTime mTime; + private final Clock mClock; private final TelephonyManager mTeleManager; private final NetworkStatsSettings mSettings; private final NetworkStatsObservers mStatsObservers; @@ -202,7 +204,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ public interface NetworkStatsSettings { public long getPollInterval(); - public long getTimeCacheMaxAge(); public boolean getSampleEnabled(); public boolean getAugmentEnabled(); @@ -281,16 +282,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private long mPersistThreshold = 2 * MB_IN_BYTES; private long mGlobalAlertBytes; - private static File getDefaultSystemDir() { + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } - private static File getDefaultBaseDir() { + private static @NonNull File getDefaultBaseDir() { File baseDir = new File(getDefaultSystemDir(), "netstats"); baseDir.mkdirs(); return baseDir; } + private static @NonNull Clock getDefaultClock() { + return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(), + Clock.systemUTC()); + } + public static NetworkStatsService create(Context context, INetworkManagementService networkManager) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); @@ -299,7 +305,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager, - wakeLock, NtpTrustedTime.getInstance(context), TelephonyManager.getDefault(), + wakeLock, getDefaultClock(), TelephonyManager.getDefault(), new DefaultNetworkStatsSettings(context), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir()); @@ -313,13 +319,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @VisibleForTesting NetworkStatsService(Context context, INetworkManagementService networkManager, - AlarmManager alarmManager, PowerManager.WakeLock wakeLock, TrustedTime time, + AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, TelephonyManager teleManager, NetworkStatsSettings settings, NetworkStatsObservers statsObservers, File systemDir, File baseDir) { mContext = checkNotNull(context, "missing Context"); mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); mAlarmManager = checkNotNull(alarmManager, "missing AlarmManager"); - mTime = checkNotNull(time, "missing TrustedTime"); + mClock = checkNotNull(clock, "missing Clock"); mSettings = checkNotNull(settings, "missing NetworkStatsSettings"); mTeleManager = checkNotNull(teleManager, "missing TelephonyManager"); mWakeLock = checkNotNull(wakeLock, "missing WakeLock"); @@ -413,8 +419,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); + final long currentTime = mClock.millis(); // persist any pending stats mDevRecorder.forcePersistLocked(currentTime); @@ -831,8 +836,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // update and persist if beyond new thresholds - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); + final long currentTime = mClock.millis(); synchronized (mStatsLock) { if (!mSystemReady) return; @@ -1170,8 +1174,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ @GuardedBy("mStatsLock") private void bootstrapStatsLocked() { - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); + final long currentTime = mClock.millis(); try { recordSnapshotLocked(currentTime); @@ -1183,11 +1186,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private void performPoll(int flags) { - // try refreshing time source when stale - if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { - mTime.forceRefresh(); - } - synchronized (mStatsLock) { mWakeLock.acquire(); @@ -1215,8 +1213,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; // TODO: consider marking "untrusted" times in historical stats - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); + final long currentTime = mClock.millis(); try { recordSnapshotLocked(currentTime); @@ -1268,7 +1265,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private void performSampleLocked() { // TODO: migrate trustedtime fixes to separate binary log events - final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1; + final long currentTime = mClock.millis(); NetworkTemplate template; NetworkStats.Entry devTotal; @@ -1285,7 +1282,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - trustedTime); + currentTime); // collect wifi sample template = buildTemplateWifiWildcard(); @@ -1297,7 +1294,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - trustedTime); + currentTime); } /** @@ -1621,10 +1618,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getGlobalLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); } @Override - public long getTimeCacheMaxAge() { - return getGlobalLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS); - } - @Override public long getGlobalAlertBytes(long def) { return getGlobalLong(NETSTATS_GLOBAL_ALERT_BYTES, def); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 3800017f0a08..548f15419798 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1836,6 +1836,10 @@ public class NotificationManagerService extends SystemService { if (index >= 0) { record = mToastQueue.get(index); record.update(duration); + try { + record.callback.hide(); + } catch (RemoteException e) { + } record.update(callback); } else { Binder token = new Binder(); diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 4bc4a7ecc055..7467954918d8 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -544,7 +544,28 @@ public final class OverlayManagerService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - return mImpl.setEnabledExclusive(packageName, userId); + return mImpl.setEnabledExclusive(packageName, false /* withinCategory */, + userId); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override + public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId) + throws RemoteException { + enforceChangeOverlayPackagesPermission("setEnabled"); + userId = handleIncomingUser(userId, "setEnabled"); + if (packageName == null) { + return false; + } + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + return mImpl.setEnabledExclusive(packageName, true /* withinCategory */, + userId); } } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index 6e02db7b25ea..a027fc6f2580 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -35,6 +35,8 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; +import libcore.util.Objects; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.Iterator; @@ -103,12 +105,14 @@ final class OverlayManagerServiceImpl { for (int i = 0; i < overlayPackagesSize; i++) { final PackageInfo overlayPackage = overlayPackages.get(i); final OverlayInfo oi = storedOverlayInfos.get(overlayPackage.packageName); - if (oi == null || !oi.targetPackageName.equals(overlayPackage.overlayTarget)) { + if (oi == null || !oi.targetPackageName.equals(overlayPackage.overlayTarget) + || !Objects.equal(oi.category, overlayPackage.overlayCategory)) { // Update the overlay if it didn't exist or had the wrong target package. mSettings.init(overlayPackage.packageName, newUserId, overlayPackage.overlayTarget, overlayPackage.applicationInfo.getBaseCodePath(), - overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority); + overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority, + overlayPackage.overlayCategory); if (oi == null) { // This overlay does not exist in our settings. @@ -259,7 +263,8 @@ final class OverlayManagerServiceImpl { mSettings.init(packageName, userId, overlayPackage.overlayTarget, overlayPackage.applicationInfo.getBaseCodePath(), - overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority); + overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority, + overlayPackage.overlayCategory); try { if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) { mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId); @@ -320,7 +325,7 @@ final class OverlayManagerServiceImpl { if (!oldOi.targetPackageName.equals(pkg.overlayTarget)) { mSettings.init(packageName, userId, pkg.overlayTarget, pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(), - pkg.overlayPriority); + pkg.overlayPriority, pkg.overlayCategory); } if (updateState(pkg.overlayTarget, packageName, userId, 0)) { @@ -394,10 +399,11 @@ final class OverlayManagerServiceImpl { } } - boolean setEnabledExclusive(@NonNull final String packageName, final int userId) { + boolean setEnabledExclusive(@NonNull final String packageName, boolean withinCategory, + final int userId) { if (DEBUG) { - Slog.d(TAG, String.format("setEnabledExclusive packageName=%s userId=%d", packageName, - userId)); + Slog.d(TAG, String.format("setEnabledExclusive packageName=%s" + + " withinCategory=%s userId=%d", packageName, withinCategory, userId)); } final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); @@ -428,6 +434,11 @@ final class OverlayManagerServiceImpl { // Don't touch static overlays. continue; } + if (withinCategory && !Objects.equal(disabledOverlayPackageInfo.overlayCategory, + oi.category)) { + // Don't touch overlays from other categories. + continue; + } // Disable the overlay. modified |= mSettings.setEnabled(disabledOverlayPackageName, userId, false); diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java index a80cae4dcb4b..e57fa0b51d39 100644 --- a/services/core/java/com/android/server/om/OverlayManagerSettings.java +++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java @@ -20,10 +20,7 @@ import static com.android.server.om.OverlayManagerService.DEBUG; import static com.android.server.om.OverlayManagerService.TAG; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.om.OverlayInfo; -import android.os.UserHandle; -import android.util.AndroidRuntimeException; import android.util.ArrayMap; import android.util.Slog; import android.util.Xml; @@ -67,11 +64,11 @@ final class OverlayManagerSettings { void init(@NonNull final String packageName, final int userId, @NonNull final String targetPackageName, @NonNull final String baseCodePath, - boolean isStatic, int priority) { + boolean isStatic, int priority, String overlayCategory) { remove(packageName, userId); final SettingsItem item = new SettingsItem(packageName, userId, targetPackageName, baseCodePath, - isStatic, priority); + isStatic, priority, overlayCategory); if (isStatic) { int i; for (i = mItems.size() - 1; i >= 0; i--) { @@ -292,6 +289,7 @@ final class OverlayManagerSettings { pw.print("mState.............: "); pw.println(OverlayInfo.stateToString(item.getState())); pw.print("mIsEnabled.........: "); pw.println(item.isEnabled()); pw.print("mIsStatic..........: "); pw.println(item.isStatic()); + pw.print("mCategory..........: "); pw.println(item.mCategory); pw.decreaseIndent(); pw.println("}"); @@ -317,6 +315,7 @@ final class OverlayManagerSettings { private static final String ATTR_TARGET_PACKAGE_NAME = "targetPackageName"; private static final String ATTR_IS_STATIC = "isStatic"; private static final String ATTR_PRIORITY = "priority"; + private static final String ATTR_CATEGORY = "category"; private static final String ATTR_USER_ID = "userId"; private static final String ATTR_VERSION = "version"; @@ -371,9 +370,10 @@ final class OverlayManagerSettings { final boolean isEnabled = XmlUtils.readBooleanAttribute(parser, ATTR_IS_ENABLED); final boolean isStatic = XmlUtils.readBooleanAttribute(parser, ATTR_IS_STATIC); final int priority = XmlUtils.readIntAttribute(parser, ATTR_PRIORITY); + final String category = XmlUtils.readStringAttribute(parser, ATTR_CATEGORY); - return new SettingsItem(packageName, userId, targetPackageName, baseCodePath, state, - isEnabled, isStatic, priority); + return new SettingsItem(packageName, userId, targetPackageName, baseCodePath, + state, isEnabled, isStatic, priority, category); } public static void persist(@NonNull final ArrayList<SettingsItem> table, @@ -405,6 +405,7 @@ final class OverlayManagerSettings { XmlUtils.writeBooleanAttribute(xml, ATTR_IS_ENABLED, item.mIsEnabled); XmlUtils.writeBooleanAttribute(xml, ATTR_IS_STATIC, item.mIsStatic); XmlUtils.writeIntAttribute(xml, ATTR_PRIORITY, item.mPriority); + XmlUtils.writeStringAttribute(xml, ATTR_CATEGORY, item.mCategory); xml.endTag(null, TAG_ITEM); } } @@ -419,17 +420,19 @@ final class OverlayManagerSettings { private OverlayInfo mCache; private boolean mIsStatic; private int mPriority; + private final String mCategory; SettingsItem(@NonNull final String packageName, final int userId, @NonNull final String targetPackageName, @NonNull final String baseCodePath, final @OverlayInfo.State int state, final boolean isEnabled, final boolean isStatic, - final int priority) { + final int priority, String category) { mPackageName = packageName; mUserId = userId; mTargetPackageName = targetPackageName; mBaseCodePath = baseCodePath; mState = state; mIsEnabled = isEnabled; + mCategory = category; mCache = null; mIsStatic = isStatic; mPriority = priority; @@ -437,9 +440,9 @@ final class OverlayManagerSettings { SettingsItem(@NonNull final String packageName, final int userId, @NonNull final String targetPackageName, @NonNull final String baseCodePath, - final boolean isStatic, final int priority) { + final boolean isStatic, final int priority, String category) { this(packageName, userId, targetPackageName, baseCodePath, OverlayInfo.STATE_UNKNOWN, - false, isStatic, priority); + false, isStatic, priority, category); } private String getTargetPackageName() { @@ -491,8 +494,8 @@ final class OverlayManagerSettings { private OverlayInfo getOverlayInfo() { if (mCache == null) { - mCache = new OverlayInfo(mPackageName, mTargetPackageName, mBaseCodePath, mState, - mUserId); + mCache = new OverlayInfo(mPackageName, mTargetPackageName, mCategory, mBaseCodePath, + mState, mUserId); } return mCache; } diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java index 29ddaf49e200..54bb115c5405 100644 --- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java +++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java @@ -56,6 +56,8 @@ final class OverlayManagerShellCommand extends ShellCommand { return runEnableDisable(true); case "disable": return runEnableDisable(false); + case "enable-exclusive": + return runEnableExclusive(); case "set-priority": return runSetPriority(); default: @@ -86,6 +88,10 @@ final class OverlayManagerShellCommand extends ShellCommand { out.println(" Enable overlay package PACKAGE."); out.println(" disable [--user USER_ID] PACKAGE"); out.println(" Disable overlay package PACKAGE."); + out.println(" enable-exclusive [--user USER_ID] [--category] PACKAGE"); + out.println(" Enable overlay package PACKAGE and disable all other overlays for"); + out.println(" its target package. If the --category option is given, only disables"); + out.println(" other overlays in the same category."); out.println(" set-priority [--user USER_ID] PACKAGE PARENT|lowest|highest"); out.println(" Change the priority of the overlay PACKAGE to be just higher than"); out.println(" the priority of PACKAGE_PARENT If PARENT is the special keyword"); @@ -157,6 +163,33 @@ final class OverlayManagerShellCommand extends ShellCommand { return mInterface.setEnabled(packageName, enable, userId) ? 0 : 1; } + private int runEnableExclusive() throws RemoteException { + final PrintWriter err = getErrPrintWriter(); + + int userId = UserHandle.USER_SYSTEM; + boolean inCategory = false; + String opt; + while ((opt = getNextOption()) != null) { + switch (opt) { + case "--user": + userId = UserHandle.parseUserArg(getNextArgRequired()); + break; + case "--category": + inCategory = true; + break; + default: + err.println("Error: Unknown option: " + opt); + return 1; + } + } + final String overlay = getNextArgRequired(); + if (inCategory) { + return mInterface.setEnabledExclusiveInCategory(overlay, userId) ? 0 : 1; + } else { + return mInterface.setEnabledExclusive(overlay, true, userId) ? 0 : 1; + } + } + private int runSetPriority() throws RemoteException { final PrintWriter err = getErrPrintWriter(); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c47381a8f00b..f23918e7e85c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -20948,7 +20948,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); pw.println(" check-permission <permission> <package> [<user>]: does pkg hold perm?"); pw.println(" dexopt: dump dexopt state"); pw.println(" compiler-stats: dump compiler statistics"); - pw.println(" enabled-overlays: dump list of enabled overlay packages"); pw.println(" service-permissions: dump permissions required by services"); pw.println(" <package.name>: info about given package"); return; @@ -22230,8 +22229,16 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e); } } - // Prepare the application profiles. - mArtManagerService.prepareAppProfiles(pkg, userId); + // Prepare the application profiles only for upgrades and first boot (so that we don't + // repeat the same operation at each boot). + // We only have to cover the upgrade and first boot here because for app installs we + // prepare the profiles before invoking dexopt (in installPackageLI). + // + // We also have to cover non system users because we do not call the usual install package + // methods for them. + if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) { + mArtManagerService.prepareAppProfiles(pkg, userId); + } if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) { // TODO: mark this structure as dirty so we persist it! diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index b5fe9ea49b86..a38cbda245ca 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -4637,6 +4637,11 @@ public final class Settings { pw.print(prefix); pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC); pw.println(); + if (ps.pkg.mOverlayTarget != null) { + pw.print(prefix); pw.print(" overlayTarget="); pw.println(ps.pkg.mOverlayTarget); + pw.print(prefix); pw.print(" overlayCategory="); pw.println(ps.pkg.mOverlayCategory); + } + if (ps.pkg != null && ps.pkg.permissions != null && ps.pkg.permissions.size() > 0) { final ArrayList<PackageParser.Permission> perms = ps.pkg.permissions; pw.print(prefix); pw.println(" declared permissions:"); diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index c5cfb8e0ef9b..4abcce16f777 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -25,6 +25,7 @@ import android.app.ActivityManager; import android.app.DownloadManager; import android.app.admin.DevicePolicyManager; import android.companion.CompanionDeviceManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -52,6 +53,7 @@ import android.provider.ContactsContract; import android.provider.MediaStore; import android.provider.Telephony.Sms.Intents; import android.security.Credentials; +import android.service.textclassifier.TextClassifierService; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; @@ -826,6 +828,24 @@ public final class DefaultPermissionGrantPolicy { STORAGE_PERMISSIONS, true, userId); } + // TextClassifier Service + ComponentName textClassifierComponent = + TextClassifierService.getServiceComponentName(mContext); + if (textClassifierComponent != null) { + Intent textClassifierServiceIntent = new Intent(TextClassifierService.SERVICE_INTERFACE) + .setComponent(textClassifierComponent); + PackageParser.Package textClassifierPackage = + getDefaultSystemHandlerServicePackage(textClassifierServiceIntent, userId); + if (textClassifierPackage != null + && doesPackageSupportRuntimePermissions(textClassifierPackage)) { + grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, true, userId); + grantRuntimePermissions(textClassifierPackage, SMS_PERMISSIONS, true, userId); + grantRuntimePermissions(textClassifierPackage, CALENDAR_PERMISSIONS, true, userId); + grantRuntimePermissions(textClassifierPackage, LOCATION_PERMISSIONS, true, userId); + grantRuntimePermissions(textClassifierPackage, CONTACTS_PERMISSIONS, true, userId); + } + } + if (mPermissionGrantedCallback != null) { mPermissionGrantedCallback.onDefaultRuntimePermissionsGranted(userId); } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index d9bcc5c92591..e77dd7b90d5d 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -5226,9 +5226,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } final int cutoutMode = attrs.layoutInDisplayCutoutMode; + final boolean attachedInParent = attached != null && !layoutInScreen; // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in // the cutout safe zone. - if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) { + // Windows that are attached to a parent and laid out in said parent are already avoiding + // the cutout according to that parent and don't need to be further constrained. + if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !attachedInParent) { final Rect displayCutoutSafeExceptMaybeTop = mTmpRect; displayCutoutSafeExceptMaybeTop.set(displayFrames.mDisplayCutoutSafe); if (layoutInScreen && layoutInsetDecor && !requestedFullscreen diff --git a/services/core/java/com/android/server/stats/OWNERS b/services/core/java/com/android/server/stats/OWNERS new file mode 100644 index 000000000000..8d7f8822f78e --- /dev/null +++ b/services/core/java/com/android/server/stats/OWNERS @@ -0,0 +1,9 @@ +bookatz@google.com +cjyu@google.com +dwchen@google.com +joeo@google.com +singhtejinder@google.com +stlafon@google.com +yaochen@google.com +yanglu@google.com +yro@google.com
\ No newline at end of file diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index fa7e53594781..d6359b8cbee3 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -16,8 +16,10 @@ package com.android.server.stats; import android.annotation.Nullable; +import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.PendingIntent; +import android.app.ProcessMemoryState; import android.app.StatsManager; import android.bluetooth.BluetoothActivityEnergyInfo; import android.bluetooth.BluetoothAdapter; @@ -128,7 +130,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { synchronized (sStatsdLock) { sStatsd = fetchStatsdService(); if (sStatsd == null) { - Slog.w(TAG, "Could not access statsd"); + Slog.w(TAG, "Could not access statsd for UserUpdateReceiver"); return; } try { @@ -143,7 +145,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } }; mShutdownEventReceiver = new ShutdownEventReceiver(); - Slog.w(TAG, "Registered receiver for ACTION_PACKAGE_REPLACE AND ADDED."); + if (DEBUG) Slog.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED."); PowerProfile powerProfile = new PowerProfile(context); final int numClusters = powerProfile.getNumCpuClusters(); mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters]; @@ -216,12 +218,12 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { PackageManager pm = context.getPackageManager(); final List<UserInfo> users = um.getUsers(true); if (DEBUG) { - Slog.w(TAG, "Iterating over " + users.size() + " profiles."); + Slog.d(TAG, "Iterating over " + users.size() + " profiles."); } - List<Integer> uids = new ArrayList(); - List<Long> versions = new ArrayList(); - List<String> apps = new ArrayList(); + List<Integer> uids = new ArrayList<>(); + List<Long> versions = new ArrayList<>(); + List<String> apps = new ArrayList<>(); // Add in all the apps for every user/profile. for (UserInfo profile : users) { @@ -237,7 +239,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { sStatsd.informAllUidData(toIntArray(uids), toLongArray(versions), apps.toArray(new String[apps.size()])); if (DEBUG) { - Slog.w(TAG, "Sent data for " + uids.size() + " apps"); + Slog.d(TAG, "Sent data for " + uids.size() + " apps"); } } @@ -712,6 +714,24 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pulledData.add(e); } + private void pullProcessMemoryState(int tagId, List<StatsLogEventWrapper> pulledData) { + List<ProcessMemoryState> processMemoryStates = + LocalServices.getService(ActivityManagerInternal.class) + .getMemoryStateForProcesses(); + for (ProcessMemoryState processMemoryState : processMemoryStates) { + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 8 /* fields */); + e.writeInt(processMemoryState.uid); + e.writeString(processMemoryState.processName); + e.writeInt(processMemoryState.oomScore); + e.writeLong(processMemoryState.pgfault); + e.writeLong(processMemoryState.pgmajfault); + e.writeLong(processMemoryState.rssInBytes); + e.writeLong(processMemoryState.cacheInBytes); + e.writeLong(processMemoryState.swapInBytes); + pulledData.add(e); + } + } + /** * Pulls various data. */ @@ -720,7 +740,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { enforceCallingPermission(); if (DEBUG) Slog.d(TAG, "Pulling " + tagId); - List<StatsLogEventWrapper> ret = new ArrayList(); + List<StatsLogEventWrapper> ret = new ArrayList<>(); switch (tagId) { case StatsLog.WIFI_BYTES_TRANSFER: { pullWifiBytesTransfer(tagId, ret); @@ -774,6 +794,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullDiskSpace(tagId, ret); break; } + case StatsLog.PROCESS_MEMORY_STATE: { + pullProcessMemoryState(tagId, ret); + break; + } default: Slog.w(TAG, "No such tagId data as " + tagId); return null; @@ -868,7 +892,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } sStatsd = fetchStatsdService(); if (sStatsd == null) { - Slog.w(TAG, "Could not access statsd"); + Slog.i(TAG, "Could not yet find statsd to tell it that StatsCompanion is alive."); return; } if (DEBUG) Slog.d(TAG, "Saying hi to statsd"); @@ -908,6 +932,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } finally { restoreCallingIdentity(token); } + Slog.i(TAG, "Told statsd that StatsCompanionService is alive."); } catch (RemoteException e) { Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e); forgetEverything(); diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index ae0f412a99bb..35fc99fe4612 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -34,6 +34,7 @@ import android.view.SurfaceControl.Transaction; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; +import java.lang.ref.WeakReference; import java.util.ArrayList; /** @@ -48,13 +49,7 @@ class RemoteAnimationController { private final ArrayList<RemoteAnimationAdapterWrapper> mPendingAnimations = new ArrayList<>(); private final Rect mTmpRect = new Rect(); private final Handler mHandler; - - private final IRemoteAnimationFinishedCallback mFinishedCallback = new Stub() { - @Override - public void onAnimationFinished() throws RemoteException { - RemoteAnimationController.this.onAnimationFinished(); - } - }; + private FinishedCallback mFinishedCallback; private final Runnable mTimeoutRunnable = () -> { onAnimationFinished(); @@ -96,6 +91,7 @@ class RemoteAnimationController { // Scale the timeout with the animator scale the controlling app is using. mHandler.postDelayed(mTimeoutRunnable, (long) (TIMEOUT_MS * mService.getCurrentAnimatorScale())); + mFinishedCallback = new FinishedCallback(this); final RemoteAnimationTarget[] animations = createAnimations(); mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> { @@ -124,6 +120,7 @@ class RemoteAnimationController { private void onAnimationFinished() { mHandler.removeCallbacks(mTimeoutRunnable); synchronized (mService.mWindowMap) { + releaseFinishedCallback(); mService.openSurfaceTransaction(); try { for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { @@ -144,6 +141,41 @@ class RemoteAnimationController { } } + private void releaseFinishedCallback() { + if (mFinishedCallback != null) { + mFinishedCallback.release(); + mFinishedCallback = null; + } + } + + private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub { + + RemoteAnimationController mOuter; + + FinishedCallback(RemoteAnimationController outer) { + mOuter = outer; + } + + @Override + public void onAnimationFinished() throws RemoteException { + if (mOuter != null) { + mOuter.onAnimationFinished(); + + // In case the client holds on to the finish callback, make sure we don't leak + // RemoteAnimationController which in turn would leak the runner on the client. + mOuter = null; + } + } + + /** + * Marks this callback as not be used anymore by releasing the reference to the outer class + * to prevent memory leak. + */ + void release() { + mOuter = null; + } + }; + private class RemoteAnimationAdapterWrapper implements AnimationAdapter { private final AppWindowToken mAppWindowToken; @@ -212,6 +244,7 @@ class RemoteAnimationController { mPendingAnimations.remove(this); if (mPendingAnimations.isEmpty()) { mHandler.removeCallbacks(mTimeoutRunnable); + releaseFinishedCallback(); invokeAnimationCancelled(); } } diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 8fd5be2a45ff..c2771e4b931f 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -51,6 +51,7 @@ static jmethodID method_setGnssYearOfHardware; static jmethodID method_setGnssHardwareModelName; static jmethodID method_xtraDownloadRequest; static jmethodID method_reportNiNotification; +static jmethodID method_requestLocation; static jmethodID method_requestRefLocation; static jmethodID method_requestSetID; static jmethodID method_requestUtcTime; @@ -346,6 +347,34 @@ static jobject translateLocation(JNIEnv* env, const GnssLocation& location) { return object.get(); } +static GnssLocation createGnssLocation( + jint gnssLocationFlags, + jdouble latitudeDegrees, + jdouble longitudeDegrees, + jdouble altitudeMeters, + jfloat speedMetersPerSec, + jfloat bearingDegrees, + jfloat horizontalAccuracyMeters, + jfloat verticalAccuracyMeters, + jfloat speedAccuracyMetersPerSecond, + jfloat bearingAccuracyDegrees, + jlong timestamp) { + GnssLocation location; + location.gnssLocationFlags = static_cast<uint16_t>(gnssLocationFlags); + location.latitudeDegrees = static_cast<double>(latitudeDegrees); + location.longitudeDegrees = static_cast<double>(longitudeDegrees); + location.altitudeMeters = static_cast<double>(altitudeMeters); + location.speedMetersPerSec = static_cast<float>(speedMetersPerSec); + location.bearingDegrees = static_cast<float>(bearingDegrees); + location.horizontalAccuracyMeters = static_cast<float>(horizontalAccuracyMeters); + location.verticalAccuracyMeters = static_cast<float>(verticalAccuracyMeters); + location.speedAccuracyMetersPerSecond = static_cast<float>(speedAccuracyMetersPerSecond); + location.bearingAccuracyDegrees = static_cast<float>(bearingAccuracyDegrees); + location.timestamp = static_cast<uint64_t>(timestamp); + + return location; +} + /* * GnssCallback class implements the callback methods for IGnss interface. */ @@ -474,7 +503,9 @@ Return<void> GnssCallback::gnssRequestTimeCb() { } Return<void> GnssCallback::gnssRequestLocationCb(const bool independentFromGnss) { - // TODO(b/72405645): call into java implementation + JNIEnv* env = getJniEnv(); + env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss)); + checkAndClearExceptionFromCallback(env, __FUNCTION__); return Void(); } @@ -1042,6 +1073,7 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;II)V"); + method_requestLocation = env->GetMethodID(clazz, "requestLocation", "(Z)V"); method_requestRefLocation = env->GetMethodID(clazz, "requestRefLocation", "()V"); method_requestSetID = env->GetMethodID(clazz, "requestSetID", "(I)V"); method_requestUtcTime = env->GetMethodID(clazz, "requestUtcTime", "()V"); @@ -1441,6 +1473,42 @@ static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, } } +static void android_location_GnssLocationProvider_inject_best_location( + JNIEnv*, + jobject, + jint gnssLocationFlags, + jdouble latitudeDegrees, + jdouble longitudeDegrees, + jdouble altitudeMeters, + jfloat speedMetersPerSec, + jfloat bearingDegrees, + jfloat horizontalAccuracyMeters, + jfloat verticalAccuracyMeters, + jfloat speedAccuracyMetersPerSecond, + jfloat bearingAccuracyDegrees, + jlong timestamp) { + if (gnssHal_V1_1 != nullptr) { + GnssLocation location = createGnssLocation( + gnssLocationFlags, + latitudeDegrees, + longitudeDegrees, + altitudeMeters, + speedMetersPerSec, + bearingDegrees, + horizontalAccuracyMeters, + verticalAccuracyMeters, + speedAccuracyMetersPerSecond, + bearingAccuracyDegrees, + timestamp); + auto result = gnssHal_V1_1->injectBestLocation(location); + if (!result.isOk() || !result) { + ALOGE("%s: Gnss injectBestLocation() failed.", __func__); + } + } else { + ALOGE("%s: injectBestLocation() is called but gnssHal_V1_1 is not available.", __func__); + } +} + static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */, jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) { if (gnssHal != nullptr) { @@ -1996,6 +2064,9 @@ static const JNINativeMethod sMethods[] = { android_location_GnssLocationProvider_read_nmea)}, {"native_inject_time", "(JJI)V", reinterpret_cast<void *>( android_location_GnssLocationProvider_inject_time)}, + {"native_inject_best_location", + "(IDDDFFFFFFJ)V", + reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_best_location)}, {"native_inject_location", "(DDF)V", reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_location)}, diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 184e8de15973..e1b4422c83c4 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -104,6 +104,7 @@ import android.os.PersistableBundle; import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.RemoteException; +import android.os.SimpleClock; import android.os.UserHandle; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; @@ -118,7 +119,6 @@ import android.util.DataUnit; import android.util.Log; import android.util.Pair; import android.util.RecurrenceRule; -import android.util.TrustedTime; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.test.BroadcastInterceptingContext; @@ -158,6 +158,7 @@ import java.time.Clock; import java.time.Instant; import java.time.Period; import java.time.ZoneId; +import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.Calendar; @@ -215,7 +216,6 @@ public class NetworkPolicyManagerServiceTest { private @Mock IActivityManager mActivityManager; private @Mock INetworkStatsService mStatsService; private @Mock INetworkManagementService mNetworkManager; - private @Mock TrustedTime mTime; private @Mock IConnectivityManager mConnManager; private @Mock NotificationManager mNotifManager; private @Mock PackageManager mPackageManager; @@ -267,6 +267,13 @@ public class NetworkPolicyManagerServiceTest { public final @Rule NetPolicyMethodRule mNetPolicyXmlRule = new NetPolicyMethodRule(); + private final Clock mClock = new SimpleClock(ZoneOffset.UTC) { + @Override + public long millis() { + return currentTimeMillis(); + } + }; + private void registerLocalServices() { addLocalServiceMock(DeviceIdleController.LocalService.class); @@ -341,7 +348,7 @@ public class NetworkPolicyManagerServiceTest { mFutureIntent = newRestrictBackgroundChangedFuture(); mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService, - mNetworkManager, mIpm, mTime, mPolicyDir, true); + mNetworkManager, mIpm, mClock, mPolicyDir, true); mService.bindConnectivityManager(mConnManager); mPolicyListener = new NetworkPolicyListenerAnswer(mService); @@ -370,7 +377,6 @@ public class NetworkPolicyManagerServiceTest { when(mPackageManager.getPackagesForUid(UID_A)).thenReturn(new String[] {PKG_NAME_A}); when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true); when(mNetworkManager.setDataSaverModeEnabled(anyBoolean())).thenReturn(true); - expectCurrentTime(); // Prepare NPMS. mService.systemReady(mService.networkScoreAndNetworkManagementServiceReady()); @@ -940,7 +946,6 @@ public class NetworkPolicyManagerServiceTest { // which means we shouldn't push limit to interface. state = new NetworkState[] { buildWifi() }; when(mConnManager.getAllNetworkState()).thenReturn(state); - expectCurrentTime(); mPolicyListener.expect().onMeteredIfacesChanged(any()); mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); @@ -949,7 +954,6 @@ public class NetworkPolicyManagerServiceTest { // now change cycle to be on 15th, and test in early march, to verify we // pick cycle day in previous month. when(mConnManager.getAllNetworkState()).thenReturn(state); - expectCurrentTime(); // pretend that 512 bytes total have happened stats = new NetworkStats(getElapsedRealtime(), 1) @@ -996,7 +1000,6 @@ public class NetworkPolicyManagerServiceTest { final long start = parseTime("2015-11-01T00:00Z"); final long end = parseTime("2015-11-07T00:00Z"); setCurrentTimeMillis(end); - expectCurrentTime(); // Normal usage means no notification { @@ -1096,7 +1099,6 @@ public class NetworkPolicyManagerServiceTest { final long start = parseTime("2015-11-01T00:00Z"); final long end = parseTime("2015-11-07T00:00Z"); setCurrentTimeMillis(end); - expectCurrentTime(); // Using 20% data in 20% time is normal { @@ -1139,7 +1141,6 @@ public class NetworkPolicyManagerServiceTest { .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L); { - expectCurrentTime(); when(mConnManager.getAllNetworkState()).thenReturn(state); when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())).thenReturn(stats.getTotalBytes()); @@ -1474,14 +1475,6 @@ public class NetworkPolicyManagerServiceTest { return new NetworkState(info, prop, networkCapabilities, null, null, TEST_SSID); } - private void expectCurrentTime() throws Exception { - when(mTime.forceRefresh()).thenReturn(false); - when(mTime.hasCache()).thenReturn(true); - when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis()); - when(mTime.getCacheAge()).thenReturn(0L); - when(mTime.getCacheCertainty()).thenReturn(0L); - } - private void expectHasInternetPermission(int uid, boolean hasIt) throws Exception { when(mIpm.checkUidPermission(Manifest.permission.INTERNET, uid)).thenReturn( hasIt ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED); diff --git a/tests/net/java/android/net/IpSecTransformTest.java b/tests/net/java/android/net/IpSecTransformTest.java index b4342df58549..ffd1f063e48b 100644 --- a/tests/net/java/android/net/IpSecTransformTest.java +++ b/tests/net/java/android/net/IpSecTransformTest.java @@ -17,6 +17,7 @@ package android.net; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import android.support.test.filters.SmallTest; @@ -56,6 +57,6 @@ public class IpSecTransformTest { IpSecTransform config1 = new IpSecTransform(null, config); IpSecTransform config2 = new IpSecTransform(null, config); - assertFalse(IpSecTransform.equals(config1, config2)); + assertTrue(IpSecTransform.equals(config1, config2)); } } diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 0f26edb28009..b1b05e8b86ba 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -87,12 +87,11 @@ import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; +import android.os.SimpleClock; import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import android.telephony.TelephonyManager; -import android.util.Log; -import android.util.TrustedTime; import com.android.internal.net.VpnInfo; import com.android.internal.util.test.BroadcastInterceptingContext; @@ -111,6 +110,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.io.File; +import java.time.Clock; +import java.time.ZoneOffset; import java.util.Objects; /** @@ -155,7 +156,6 @@ public class NetworkStatsServiceTest { private File mStatsDir; private @Mock INetworkManagementService mNetManager; - private @Mock TrustedTime mTime; private @Mock NetworkStatsSettings mSettings; private @Mock IConnectivityManager mConnManager; private @Mock IBinder mBinder; @@ -167,6 +167,13 @@ public class NetworkStatsServiceTest { private INetworkStatsSession mSession; private INetworkManagementEventObserver mNetworkObserver; + private final Clock mClock = new SimpleClock(ZoneOffset.UTC) { + @Override + public long millis() { + return currentTimeMillis(); + } + }; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -184,7 +191,7 @@ public class NetworkStatsServiceTest { powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mService = new NetworkStatsService( - mServiceContext, mNetManager, mAlarmManager, wakeLock, mTime, + mServiceContext, mNetManager, mAlarmManager, wakeLock, mClock, TelephonyManager.getDefault(), mSettings, new NetworkStatsObservers(), mStatsDir, getBaseDir(mStatsDir)); mHandlerThread = new HandlerThread("HandlerThread"); @@ -196,7 +203,6 @@ public class NetworkStatsServiceTest { mElapsedRealtime = 0L; - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsUidDetail(buildEmptyStats()); expectSystemReady(); @@ -221,7 +227,6 @@ public class NetworkStatsServiceTest { mStatsDir = null; mNetManager = null; - mTime = null; mSettings = null; mConnManager = null; @@ -233,7 +238,6 @@ public class NetworkStatsServiceTest { public void testNetworkStatsWifi() throws Exception { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); @@ -248,7 +252,6 @@ public class NetworkStatsServiceTest { // modify some number on wifi, and trigger poll event incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L)); @@ -262,7 +265,6 @@ public class NetworkStatsServiceTest { // and bump forward again, with counters going higher. this is // important, since polling should correctly subtract last snapshot. incrementCurrentTime(DAY_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 4096L, 4L, 8192L, 8L)); @@ -280,7 +282,6 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); @@ -295,7 +296,6 @@ public class NetworkStatsServiceTest { // modify some number on wifi, and trigger poll event incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 1024L, 8L, 2048L, 16L)); @@ -324,13 +324,11 @@ public class NetworkStatsServiceTest { // graceful shutdown system, which should trigger persist of stats, and // clear any values in memory. - expectCurrentTime(); expectDefaultSettings(); mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN)); assertStatsFilesExist(true); // boot through serviceReady() again - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsUidDetail(buildEmptyStats()); expectSystemReady(); @@ -358,7 +356,6 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. - expectCurrentTime(); expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); @@ -370,7 +367,6 @@ public class NetworkStatsServiceTest { // modify some number on wifi, and trigger poll event incrementCurrentTime(2 * HOUR_IN_MILLIS); - expectCurrentTime(); expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 512L, 4L, 512L, 4L)); @@ -386,7 +382,6 @@ public class NetworkStatsServiceTest { // now change bucket duration setting and trigger another poll with // exact same values, which should resize existing buckets. - expectCurrentTime(); expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -403,7 +398,6 @@ public class NetworkStatsServiceTest { @Test public void testUidStatsAcrossNetworks() throws Exception { // pretend first mobile network comes online - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildMobile3gState(IMSI_1)); expectNetworkStatsSummary(buildEmptyStats()); @@ -415,7 +409,6 @@ public class NetworkStatsServiceTest { // create some traffic on first network incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); @@ -437,7 +430,6 @@ public class NetworkStatsServiceTest { // now switch networks; this also tests that we're okay with interfaces // disappearing, to verify we don't count backwards. incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildMobile3gState(IMSI_2)); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) @@ -454,7 +446,6 @@ public class NetworkStatsServiceTest { // create traffic on second network incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 2176L, 17L, 1536L, 12L)); @@ -483,7 +474,6 @@ public class NetworkStatsServiceTest { @Test public void testUidRemovedIsMoved() throws Exception { // pretend that network comes online - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); @@ -495,7 +485,6 @@ public class NetworkStatsServiceTest { // create some traffic incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L)); @@ -517,7 +506,6 @@ public class NetworkStatsServiceTest { // now pretend two UIDs are uninstalled, which should migrate stats to // special "removed" bucket. - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L)); @@ -545,7 +533,6 @@ public class NetworkStatsServiceTest { @Test public void testUid3g4gCombinedByTemplate() throws Exception { // pretend that network comes online - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildMobile3gState(IMSI_1)); expectNetworkStatsSummary(buildEmptyStats()); @@ -557,7 +544,6 @@ public class NetworkStatsServiceTest { // create some traffic incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) @@ -573,7 +559,6 @@ public class NetworkStatsServiceTest { // now switch over to 4g network incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildMobile4gState(TEST_IFACE2)); expectNetworkStatsSummary(buildEmptyStats()); @@ -588,7 +573,6 @@ public class NetworkStatsServiceTest { // create traffic on second network incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) @@ -607,7 +591,6 @@ public class NetworkStatsServiceTest { @Test public void testSummaryForAllUid() throws Exception { // pretend that network comes online - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); @@ -619,7 +602,6 @@ public class NetworkStatsServiceTest { // create some traffic for two apps incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) @@ -637,7 +619,6 @@ public class NetworkStatsServiceTest { // now create more traffic in next hour, but only for one app incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) @@ -669,7 +650,6 @@ public class NetworkStatsServiceTest { @Test public void testForegroundBackground() throws Exception { // pretend that network comes online - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); @@ -681,7 +661,6 @@ public class NetworkStatsServiceTest { // create some initial traffic incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) @@ -697,7 +676,6 @@ public class NetworkStatsServiceTest { // now switch to foreground incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) @@ -730,7 +708,6 @@ public class NetworkStatsServiceTest { @Test public void testMetered() throws Exception { // pretend that network comes online - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildWifiState(true /* isMetered */)); expectNetworkStatsSummary(buildEmptyStats()); @@ -742,7 +719,6 @@ public class NetworkStatsServiceTest { // create some initial traffic incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); // Note that all traffic from NetworkManagementService is tagged as METERED_NO, ROAMING_NO @@ -772,7 +748,6 @@ public class NetworkStatsServiceTest { @Test public void testRoaming() throws Exception { // pretend that network comes online - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */)); expectNetworkStatsSummary(buildEmptyStats()); @@ -784,7 +759,6 @@ public class NetworkStatsServiceTest { // Create some traffic incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); // Note that all traffic from NetworkManagementService is tagged as METERED_NO and @@ -813,7 +787,6 @@ public class NetworkStatsServiceTest { @Test public void testTethering() throws Exception { // pretend first mobile network comes online - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildMobile3gState(IMSI_1)); expectNetworkStatsSummary(buildEmptyStats()); @@ -825,7 +798,6 @@ public class NetworkStatsServiceTest { // create some tethering traffic incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); // Traffic seen by kernel counters (includes software tethering). @@ -858,7 +830,6 @@ public class NetworkStatsServiceTest { public void testRegisterUsageCallback() throws Exception { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. - expectCurrentTime(); expectDefaultSettings(); expectNetworkState(buildWifiState()); expectNetworkStatsSummary(buildEmptyStats()); @@ -880,7 +851,6 @@ public class NetworkStatsServiceTest { Messenger messenger = new Messenger(latchedHandler); // Force poll - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); @@ -909,7 +879,6 @@ public class NetworkStatsServiceTest { // modify some number on wifi, and trigger poll event // not enough traffic to call data usage callback incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L)); @@ -925,7 +894,6 @@ public class NetworkStatsServiceTest { // and bump forward again, with counters going higher. this is // important, since it will trigger the data usage callback incrementCurrentTime(DAY_IN_MILLIS); - expectCurrentTime(); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 4096000L, 4L, 8192000L, 8L)); @@ -1068,7 +1036,6 @@ public class NetworkStatsServiceTest { private void expectSettings(long persistBytes, long bucketDuration, long deleteAge) throws Exception { when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS); - when(mSettings.getTimeCacheMaxAge()).thenReturn(DAY_IN_MILLIS); when(mSettings.getSampleEnabled()).thenReturn(true); final Config config = new Config(bucketDuration, deleteAge, deleteAge); @@ -1084,14 +1051,6 @@ public class NetworkStatsServiceTest { when(mSettings.getUidTagPersistBytes(anyLong())).thenReturn(MB_IN_BYTES); } - private void expectCurrentTime() throws Exception { - when(mTime.forceRefresh()).thenReturn(false); - when(mTime.hasCache()).thenReturn(true); - when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis()); - when(mTime.getCacheAge()).thenReturn(0L); - when(mTime.getCacheCertainty()).thenReturn(0L); - } - private void expectBandwidthControlCheck() throws Exception { when(mNetManager.isBandwidthControlEnabled()).thenReturn(true); } diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp index 77cee0683f3e..6f213e19e5f6 100644 --- a/tools/aapt2/ResourceValues.cpp +++ b/tools/aapt2/ResourceValues.cpp @@ -369,6 +369,19 @@ FileReference* FileReference::Clone(StringPool* new_pool) const { void FileReference::Print(std::ostream* out) const { *out << "(file) " << *path; + switch (type) { + case ResourceFile::Type::kBinaryXml: + *out << " type=XML"; + break; + case ResourceFile::Type::kProtoXml: + *out << " type=protoXML"; + break; + case ResourceFile::Type::kPng: + *out << " type=PNG"; + break; + default: + break; + } } BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) { diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 15c5eaecd102..12ab88345411 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -514,6 +514,17 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer return xml_compat_versioner.Process(context_, doc, api_range); } +ResourceFile::Type XmlFileTypeForOutputFormat(OutputFormat format) { + switch (format) { + case OutputFormat::kApk: + return ResourceFile::Type::kBinaryXml; + case OutputFormat::kProto: + return ResourceFile::Type::kProtoXml; + } + LOG_ALWAYS_FATAL("unreachable"); + return ResourceFile::Type::kUnknown; +} + bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archive_writer) { bool error = false; std::map<std::pair<ConfigDescription, StringPiece>, FileOperation> config_sorted_files; @@ -587,6 +598,9 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv } } + // Update the type that this file will be written as. + file_ref->type = XmlFileTypeForOutputFormat(options_.output_format); + file_op.xml_to_flatten->file.config = config_value->config; file_op.xml_to_flatten->file.source = file_ref->GetSource(); file_op.xml_to_flatten->file.name = ResourceName(pkg->name, type->type, entry->name); @@ -625,12 +639,16 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv << config << "' -> '" << doc->file.config << "'"); } - dst_path = - ResourceUtils::BuildResourceFileName(doc->file, context_->GetNameMangler()); - bool result = - table->AddFileReferenceMangled(doc->file.name, doc->file.config, doc->file.source, - dst_path, nullptr, context_->GetDiagnostics()); - if (!result) { + const ResourceFile& file = doc->file; + dst_path = ResourceUtils::BuildResourceFileName(file, context_->GetNameMangler()); + + std::unique_ptr<FileReference> file_ref = + util::make_unique<FileReference>(table->string_pool.MakeRef(dst_path)); + file_ref->SetSource(doc->file.source); + // Update the output format of this XML file. + file_ref->type = XmlFileTypeForOutputFormat(options_.output_format); + if (!table->AddResourceMangled(file.name, file.config, {}, std::move(file_ref), + context_->GetDiagnostics())) { return false; } } diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index 399b0c63e113..26248e51b884 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -309,6 +309,8 @@ def verify_class_names(clazz): warn(clazz, None, "S1", "Class names with acronyms should be Mtp not MTP") if re.match("[^A-Z]", clazz.name): error(clazz, None, "S1", "Class must start with uppercase char") + if clazz.name.endswith("Impl"): + error(clazz, None, None, "Don't expose your implementation details") def verify_method_names(clazz): @@ -1291,6 +1293,44 @@ def verify_tense(clazz): warn(clazz, m, None, "Unexpected tense; probably meant 'enabled'") +def verify_icu(clazz): + """Verifies that richer ICU replacements are used.""" + better = { + "java.util.TimeZone": "android.icu.util.TimeZone", + "java.util.Calendar": "android.icu.util.Calendar", + "java.util.Locale": "android.icu.util.ULocale", + "java.util.ResourceBundle": "android.icu.util.UResourceBundle", + "java.util.SimpleTimeZone": "android.icu.util.SimpleTimeZone", + "java.util.StringTokenizer": "android.icu.util.StringTokenizer", + "java.util.GregorianCalendar": "android.icu.util.GregorianCalendar", + "java.lang.Character": "android.icu.lang.UCharacter", + "java.text.BreakIterator": "android.icu.text.BreakIterator", + "java.text.Collator": "android.icu.text.Collator", + "java.text.DecimalFormatSymbols": "android.icu.text.DecimalFormatSymbols", + "java.text.NumberFormat": "android.icu.text.NumberFormat", + "java.text.DateFormatSymbols": "android.icu.text.DateFormatSymbols", + "java.text.DateFormat": "android.icu.text.DateFormat", + "java.text.SimpleDateFormat": "android.icu.text.SimpleDateFormat", + "java.text.MessageFormat": "android.icu.text.MessageFormat", + "java.text.DecimalFormat": "android.icu.text.DecimalFormat", + } + + for m in clazz.ctors + clazz.methods: + types = [] + types.extend(m.typ) + types.extend(m.args) + for arg in types: + if arg in better: + warn(clazz, m, None, "Type %s should be replaced with richer ICU type %s" % (arg, better[arg])) + + +def verify_clone(clazz): + """Verify that clone() isn't implemented; see EJ page 61.""" + for m in clazz.methods: + if m.name == "clone": + error(clazz, m, None, "Provide an explicit copy constructor instead of implementing clone()") + + def examine_clazz(clazz): """Find all style issues in the given class.""" @@ -1352,6 +1392,8 @@ def examine_clazz(clazz): verify_params(clazz) verify_services(clazz) verify_tense(clazz) + verify_icu(clazz) + verify_clone(clazz) def examine_stream(stream): diff --git a/wifi/java/android/net/wifi/rtt/LocationCivic.java b/wifi/java/android/net/wifi/rtt/LocationCivic.java deleted file mode 100644 index 610edb6399b4..000000000000 --- a/wifi/java/android/net/wifi/rtt/LocationCivic.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.wifi.rtt; - -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Arrays; -import java.util.Objects; - -/** - * Location Civic Report (LCR). - * <p> - * The information matches the IEEE 802.11-2016 LCR report. - * <p> - * Note: depending on the mechanism by which this information is returned (i.e. the API which - * returns an instance of this class) it is possibly Self Reported (by the peer). In such a case - * the information is NOT validated - use with caution. Consider validating it with other sources - * of information before using it. - */ -public final class LocationCivic implements Parcelable { - private final byte[] mData; - - /** - * Parse the raw LCR information element (byte array) and extract the LocationCivic structure. - * - * Note: any parsing errors or invalid/unexpected errors will result in a null being returned. - * - * @hide - */ - @Nullable - public static LocationCivic parseInformationElement(byte id, byte[] data) { - // TODO - return null; - } - - /** @hide */ - public LocationCivic(byte[] data) { - mData = data; - } - - /** - * Return the Location Civic data reported by the peer. - * - * @return An arbitrary location information. - */ - public byte[] getData() { - return mData; - } - - /** @hide */ - @Override - public int describeContents() { - return 0; - } - - /** @hide */ - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeByteArray(mData); - } - - public static final Parcelable.Creator<LocationCivic> CREATOR = - new Parcelable.Creator<LocationCivic>() { - @Override - public LocationCivic[] newArray(int size) { - return new LocationCivic[size]; - } - - @Override - public LocationCivic createFromParcel(Parcel in) { - byte[] data = in.createByteArray(); - - return new LocationCivic(data); - } - }; - - /** @hide */ - @Override - public String toString() { - return new StringBuilder("LCR: data=").append(Arrays.toString(mData)).toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (!(o instanceof LocationCivic)) { - return false; - } - - LocationCivic lhs = (LocationCivic) o; - - return Arrays.equals(mData, lhs.mData); - } - - @Override - public int hashCode() { - return Objects.hash(mData); - } -} diff --git a/wifi/java/android/net/wifi/rtt/LocationConfigurationInformation.java b/wifi/java/android/net/wifi/rtt/LocationConfigurationInformation.java deleted file mode 100644 index 8aba56aa0ee7..000000000000 --- a/wifi/java/android/net/wifi/rtt/LocationConfigurationInformation.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.wifi.rtt; - -import android.annotation.IntDef; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Objects; - -/** - * The Device Location Configuration Information (LCI) specifies the location information of a peer - * device (e.g. an Access Point). - * <p> - * The information matches the IEEE 802.11-2016 LCI report (Location configuration information - * report). - * <p> - * Note: depending on the mechanism by which this information is returned (i.e. the API which - * returns an instance of this class) it is possibly Self Reported (by the peer). In such a case - * the information is NOT validated - use with caution. Consider validating it with other sources - * of information before using it. - */ -public final class LocationConfigurationInformation implements Parcelable { - /** @hide */ - @IntDef({ - ALTITUDE_UNKNOWN, ALTITUDE_IN_METERS, ALTITUDE_IN_FLOORS }) - @Retention(RetentionPolicy.SOURCE) - public @interface AltitudeTypes { - } - - /** - * Define an Altitude Type returned by {@link #getAltitudeType()}. Indicates that the location - * does not specify an altitude or altitude uncertainty. The corresponding methods, - * {@link #getAltitude()} and {@link #getAltitudeUncertainty()} are not valid and will throw - * an exception. - */ - public static final int ALTITUDE_UNKNOWN = 0; - - /** - * Define an Altitude Type returned by {@link #getAltitudeType()}. Indicates that the location - * specifies the altitude and altitude uncertainty in meters. The corresponding methods, - * {@link #getAltitude()} and {@link #getAltitudeUncertainty()} return a valid value in meters. - */ - public static final int ALTITUDE_IN_METERS = 1; - - /** - * Define an Altitude Type returned by {@link #getAltitudeType()}. Indicates that the - * location specifies the altitude in floors, and does not specify an altitude uncertainty. - * The {@link #getAltitude()} method returns valid value in floors, and the - * {@link #getAltitudeUncertainty()} method is not valid and will throw an exception. - */ - public static final int ALTITUDE_IN_FLOORS = 2; - - private final double mLatitude; - private final double mLatitudeUncertainty; - private final double mLongitude; - private final double mLongitudeUncertainty; - private final int mAltitudeType; - private final double mAltitude; - private final double mAltitudeUncertainty; - - /** - * Parse the raw LCI information element (byte array) and extract the - * LocationConfigurationInformation structure. - * - * Note: any parsing errors or invalid/unexpected errors will result in a null being returned. - * - * @hide - */ - @Nullable - public static LocationConfigurationInformation parseInformationElement(byte id, byte[] data) { - // TODO - return null; - } - - /** @hide */ - public LocationConfigurationInformation(double latitude, double latitudeUncertainty, - double longitude, double longitudeUncertainty, @AltitudeTypes int altitudeType, - double altitude, double altitudeUncertainty) { - mLatitude = latitude; - mLatitudeUncertainty = latitudeUncertainty; - mLongitude = longitude; - mLongitudeUncertainty = longitudeUncertainty; - mAltitudeType = altitudeType; - mAltitude = altitude; - mAltitudeUncertainty = altitudeUncertainty; - } - - /** - * Get latitude in degrees. Values are per WGS 84 reference system. Valid values are between - * -90 and 90. - * - * @return Latitude in degrees. - */ - public double getLatitude() { - return mLatitude; - } - - /** - * Get the uncertainty of the latitude {@link #getLatitude()} in degrees. A value of 0 indicates - * an unknown uncertainty. - * - * @return Uncertainty of the latitude in degrees. - */ - public double getLatitudeUncertainty() { - return mLatitudeUncertainty; - } - - /** - * Get longitude in degrees. Values are per WGS 84 reference system. Valid values are between - * -180 and 180. - * - * @return Longitude in degrees. - */ - public double getLongitude() { - return mLongitude; - } - - /** - * Get the uncertainty of the longitude {@link #getLongitude()} ()} in degrees. A value of 0 - * indicates an unknown uncertainty. - * - * @return Uncertainty of the longitude in degrees. - */ - public double getLongitudeUncertainty() { - return mLongitudeUncertainty; - } - - /** - * Specifies the type of the altitude measurement returned by {@link #getAltitude()} and - * {@link #getAltitudeUncertainty()}. The possible values are: - * <li>{@link #ALTITUDE_UNKNOWN}: The altitude and altitude uncertainty are not provided. - * <li>{@link #ALTITUDE_IN_METERS}: The altitude and altitude uncertainty are provided in - * meters. Values are per WGS 84 reference system. - * <li>{@link #ALTITUDE_IN_FLOORS}: The altitude is provided in floors, the altitude uncertainty - * is not provided. - * - * @return The type of the altitude and altitude uncertainty. - */ - public @AltitudeTypes int getAltitudeType() { - return mAltitudeType; - } - - /** - * The altitude is interpreted according to the {@link #getAltitudeType()}. The possible values - * are: - * <li>{@link #ALTITUDE_UNKNOWN}: The altitude is not provided - this method will throw an - * exception. - * <li>{@link #ALTITUDE_IN_METERS}: The altitude is provided in meters. Values are per WGS 84 - * reference system. - * <li>{@link #ALTITUDE_IN_FLOORS}: The altitude is provided in floors. - * - * @return Altitude value whose meaning is specified by {@link #getAltitudeType()}. - */ - public double getAltitude() { - if (mAltitudeType == ALTITUDE_UNKNOWN) { - throw new IllegalStateException( - "getAltitude(): invoked on an invalid type: getAltitudeType()==UNKNOWN"); - } - return mAltitude; - } - - /** - * Only valid if the the {@link #getAltitudeType()} is equal to {@link #ALTITUDE_IN_METERS} - - * otherwise this method will throw an exception. - * <p> - * Get the uncertainty of the altitude {@link #getAltitude()} in meters. A value of 0 - * indicates an unknown uncertainty. - * - * @return Uncertainty of the altitude in meters. - */ - public double getAltitudeUncertainty() { - if (mAltitudeType != ALTITUDE_IN_METERS) { - throw new IllegalStateException( - "getAltitude(): invoked on an invalid type: getAltitudeType()!=IN_METERS"); - } - return mAltitudeUncertainty; - } - - /** @hide */ - @Override - public int describeContents() { - return 0; - } - - /** @hide */ - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeDouble(mLatitude); - dest.writeDouble(mLatitudeUncertainty); - dest.writeDouble(mLongitude); - dest.writeDouble(mLongitudeUncertainty); - dest.writeInt(mAltitudeType); - dest.writeDouble(mAltitude); - dest.writeDouble(mAltitudeUncertainty); - } - - public static final Creator<LocationConfigurationInformation> CREATOR = - new Creator<LocationConfigurationInformation>() { - @Override - public LocationConfigurationInformation[] newArray(int size) { - return new LocationConfigurationInformation[size]; - } - - @Override - public LocationConfigurationInformation createFromParcel(Parcel in) { - double latitude = in.readDouble(); - double latitudeUnc = in.readDouble(); - double longitude = in.readDouble(); - double longitudeUnc = in.readDouble(); - int altitudeType = in.readInt(); - double altitude = in.readDouble(); - double altitudeUnc = in.readDouble(); - - return new LocationConfigurationInformation(latitude, latitudeUnc, longitude, - longitudeUnc, altitudeType, altitude, altitudeUnc); - } - }; - - /** @hide */ - @Override - public String toString() { - return new StringBuilder("LCI: latitude=").append(mLatitude).append( - ", latitudeUncertainty=").append(mLatitudeUncertainty).append( - ", longitude=").append(mLongitude).append(", longitudeUncertainty=").append( - mLongitudeUncertainty).append(", altitudeType=").append(mAltitudeType).append( - ", altitude=").append(mAltitude).append(", altitudeUncertainty=").append( - mAltitudeUncertainty).toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (!(o instanceof LocationConfigurationInformation)) { - return false; - } - - LocationConfigurationInformation lhs = (LocationConfigurationInformation) o; - - return mLatitude == lhs.mLatitude && mLatitudeUncertainty == lhs.mLatitudeUncertainty - && mLongitude == lhs.mLongitude - && mLongitudeUncertainty == lhs.mLongitudeUncertainty - && mAltitudeType == lhs.mAltitudeType && mAltitude == lhs.mAltitude - && mAltitudeUncertainty == lhs.mAltitudeUncertainty; - } - - @Override - public int hashCode() { - return Objects.hash(mLatitude, mLatitudeUncertainty, mLongitude, mLongitudeUncertainty, - mAltitudeType, mAltitude, mAltitudeUncertainty); - } -} diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java index 5c9bd198e05b..05927f029aa6 100644 --- a/wifi/java/android/net/wifi/rtt/RangingResult.java +++ b/wifi/java/android/net/wifi/rtt/RangingResult.java @@ -19,6 +19,7 @@ package android.net.wifi.rtt; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.net.MacAddress; import android.net.wifi.aware.PeerHandle; import android.os.Handler; @@ -27,6 +28,7 @@ import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -40,6 +42,7 @@ import java.util.Objects; */ public final class RangingResult implements Parcelable { private static final String TAG = "RangingResult"; + private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; /** @hide */ @IntDef({STATUS_SUCCESS, STATUS_FAIL, STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC}) @@ -76,37 +79,35 @@ public final class RangingResult implements Parcelable { private final int mDistanceMm; private final int mDistanceStdDevMm; private final int mRssi; - private final LocationConfigurationInformation mLci; - private final LocationCivic mLcr; + private final byte[] mLci; + private final byte[] mLcr; private final long mTimestamp; /** @hide */ public RangingResult(@RangeResultStatus int status, @NonNull MacAddress mac, int distanceMm, - int distanceStdDevMm, int rssi, LocationConfigurationInformation lci, LocationCivic lcr, - long timestamp) { + int distanceStdDevMm, int rssi, byte[] lci, byte[] lcr, long timestamp) { mStatus = status; mMac = mac; mPeerHandle = null; mDistanceMm = distanceMm; mDistanceStdDevMm = distanceStdDevMm; mRssi = rssi; - mLci = lci; - mLcr = lcr; + mLci = lci == null ? EMPTY_BYTE_ARRAY : lci; + mLcr = lcr == null ? EMPTY_BYTE_ARRAY : lcr; mTimestamp = timestamp; } /** @hide */ public RangingResult(@RangeResultStatus int status, PeerHandle peerHandle, int distanceMm, - int distanceStdDevMm, int rssi, LocationConfigurationInformation lci, LocationCivic lcr, - long timestamp) { + int distanceStdDevMm, int rssi, byte[] lci, byte[] lcr, long timestamp) { mStatus = status; mMac = null; mPeerHandle = peerHandle; mDistanceMm = distanceMm; mDistanceStdDevMm = distanceStdDevMm; mRssi = rssi; - mLci = lci; - mLcr = lcr; + mLci = lci == null ? EMPTY_BYTE_ARRAY : lci; + mLcr = lcr == null ? EMPTY_BYTE_ARRAY : lcr; mTimestamp = timestamp; } @@ -192,13 +193,15 @@ public final class RangingResult implements Parcelable { * <p> * Note: the information is NOT validated - use with caution. Consider validating it with * other sources of information before using it. + * + * @hide */ - @Nullable - public LocationConfigurationInformation getReportedLocationConfigurationInformation() { + @SystemApi + @NonNull + public byte[] getLci() { if (mStatus != STATUS_SUCCESS) { throw new IllegalStateException( - "getReportedLocationConfigurationInformation(): invoked on an invalid result: " - + "getStatus()=" + mStatus); + "getLci(): invoked on an invalid result: getStatus()=" + mStatus); } return mLci; } @@ -208,9 +211,12 @@ public final class RangingResult implements Parcelable { * <p> * Note: the information is NOT validated - use with caution. Consider validating it with * other sources of information before using it. + * + * @hide */ - @Nullable - public LocationCivic getReportedLocationCivic() { + @SystemApi + @NonNull + public byte[] getLcr() { if (mStatus != STATUS_SUCCESS) { throw new IllegalStateException( "getReportedLocationCivic(): invoked on an invalid result: getStatus()=" @@ -256,18 +262,8 @@ public final class RangingResult implements Parcelable { dest.writeInt(mDistanceMm); dest.writeInt(mDistanceStdDevMm); dest.writeInt(mRssi); - if (mLci == null) { - dest.writeBoolean(false); - } else { - dest.writeBoolean(true); - mLci.writeToParcel(dest, flags); - } - if (mLcr == null) { - dest.writeBoolean(false); - } else { - dest.writeBoolean(true); - mLcr.writeToParcel(dest, flags); - } + dest.writeByteArray(mLci); + dest.writeByteArray(mLcr); dest.writeLong(mTimestamp); } @@ -293,16 +289,8 @@ public final class RangingResult implements Parcelable { int distanceMm = in.readInt(); int distanceStdDevMm = in.readInt(); int rssi = in.readInt(); - boolean lciPresent = in.readBoolean(); - LocationConfigurationInformation lci = null; - if (lciPresent) { - lci = LocationConfigurationInformation.CREATOR.createFromParcel(in); - } - boolean lcrPresent = in.readBoolean(); - LocationCivic lcr = null; - if (lcrPresent) { - lcr = LocationCivic.CREATOR.createFromParcel(in); - } + byte[] lci = in.createByteArray(); + byte[] lcr = in.createByteArray(); long timestamp = in.readLong(); if (peerHandlePresent) { return new RangingResult(status, peerHandle, distanceMm, distanceStdDevMm, rssi, @@ -340,7 +328,7 @@ public final class RangingResult implements Parcelable { return mStatus == lhs.mStatus && Objects.equals(mMac, lhs.mMac) && Objects.equals( mPeerHandle, lhs.mPeerHandle) && mDistanceMm == lhs.mDistanceMm && mDistanceStdDevMm == lhs.mDistanceStdDevMm && mRssi == lhs.mRssi - && Objects.equals(mLci, lhs.mLci) && Objects.equals(mLcr, lhs.mLcr) + && Arrays.equals(mLci, lhs.mLci) && Arrays.equals(mLcr, lhs.mLcr) && mTimestamp == lhs.mTimestamp; } diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java index 41c7f8644e2e..e790c3a51f6f 100644 --- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java +++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java @@ -17,7 +17,6 @@ package android.net.wifi.rtt; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -227,7 +226,6 @@ public class WifiRttManagerTest { */ @Test public void testRangingResultsParcel() { - // Note: not validating parcel code of ScanResult (assumed to work) int status = RangingResult.STATUS_SUCCESS; final MacAddress mac = MacAddress.fromString("00:01:02:03:04:05"); PeerHandle peerHandle = new PeerHandle(10); @@ -235,19 +233,8 @@ public class WifiRttManagerTest { int distanceStdDevCm = 10; int rssi = 5; long timestamp = System.currentTimeMillis(); - double latitude = 5.5; - double latitudeUncertainty = 6.5; - double longitude = 7.5; - double longitudeUncertainty = 8.5; - int altitudeType = LocationConfigurationInformation.ALTITUDE_IN_METERS; - double altitude = 9.5; - double altitudeUncertainty = 55.5; - byte[] lcrData = { 0x1, 0x2, 0x3, 0xA, 0xB, 0xC }; - - LocationConfigurationInformation lci = new LocationConfigurationInformation(latitude, - latitudeUncertainty, longitude, longitudeUncertainty, altitudeType, altitude, - altitudeUncertainty); - LocationCivic lcr = new LocationCivic(lcrData); + byte[] lci = { 0x5, 0x6, 0x7 }; + byte[] lcr = { 0x1, 0x2, 0x3, 0xA, 0xB, 0xC }; // RangingResults constructed with a MAC address RangingResult result = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi, @@ -283,81 +270,25 @@ public class WifiRttManagerTest { } /** - * Validate that LocationConfigurationInformation parcel works (produces same object on - * write/read). - */ - @Test - public void testLciParcel() { - double latitude = 1.5; - double latitudeUncertainty = 2.5; - double longitude = 3.5; - double longitudeUncertainty = 4.5; - int altitudeType = LocationConfigurationInformation.ALTITUDE_IN_FLOORS; - double altitude = 5.5; - double altitudeUncertainty = 6.5; - - LocationConfigurationInformation lci = new LocationConfigurationInformation(latitude, - latitudeUncertainty, longitude, longitudeUncertainty, altitudeType, altitude, - altitudeUncertainty); - - Parcel parcelW = Parcel.obtain(); - lci.writeToParcel(parcelW, 0); - byte[] bytes = parcelW.marshall(); - parcelW.recycle(); - - Parcel parcelR = Parcel.obtain(); - parcelR.unmarshall(bytes, 0, bytes.length); - parcelR.setDataPosition(0); - LocationConfigurationInformation rereadLci = - LocationConfigurationInformation.CREATOR.createFromParcel(parcelR); - - assertEquals(lci, rereadLci); - } - - /** - * Validate that the LCI throws an exception when accessing invalid fields an certain altitude - * types. + * Validate that RangingResults tests equal even if LCI/LCR is empty (length == 0) and null. */ @Test - public void testLciInvalidAltitudeFieldAccess() { - boolean exceptionThrown; - LocationConfigurationInformation lci = new LocationConfigurationInformation(0, 0, 0, 0, - LocationConfigurationInformation.ALTITUDE_UNKNOWN, 0, 0); - - // UNKNOWN - invalid altitude & altitude uncertainty - exceptionThrown = false; - try { - lci.getAltitude(); - } catch (IllegalStateException e) { - exceptionThrown = true; - } - assertTrue("UNKNOWN / getAltitude()", exceptionThrown); - - exceptionThrown = false; - try { - lci.getAltitudeUncertainty(); - } catch (IllegalStateException e) { - exceptionThrown = true; - } - assertTrue("UNKNOWN / getAltitudeUncertainty()", exceptionThrown); + public void testRangingResultsEqualityLciLcr() { + int status = RangingResult.STATUS_SUCCESS; + final MacAddress mac = MacAddress.fromString("00:01:02:03:04:05"); + PeerHandle peerHandle = new PeerHandle(10); + int distanceCm = 105; + int distanceStdDevCm = 10; + int rssi = 5; + long timestamp = System.currentTimeMillis(); + byte[] lci = { }; + byte[] lcr = { }; - lci = new LocationConfigurationInformation(0, 0, 0, 0, - LocationConfigurationInformation.ALTITUDE_IN_FLOORS, 0, 0); + RangingResult rr1 = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi, lci, + lcr, timestamp); + RangingResult rr2 = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi, null, + null, timestamp); - // FLOORS - invalid altitude uncertainty - exceptionThrown = false; - try { - lci.getAltitudeUncertainty(); - } catch (IllegalStateException e) { - exceptionThrown = true; - } - assertTrue("FLOORS / getAltitudeUncertainty()", exceptionThrown); - - // and good accesses just in case - lci.getAltitude(); - lci = new LocationConfigurationInformation(0, 0, 0, 0, - LocationConfigurationInformation.ALTITUDE_IN_METERS, 0, 0); - lci.getAltitude(); - lci.getAltitudeUncertainty(); + assertEquals(rr1, rr2); } } |