Merge "Sets accessibility title for autofill dataset picker."
diff --git a/api/current.txt b/api/current.txt
index 2644372..74953c2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5548,12 +5548,14 @@
method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>);
method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>);
method public void deleteNotificationChannel(java.lang.String);
+ method public void deleteNotificationChannelGroup(java.lang.String);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
method public int getImportance();
method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
+ method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
@@ -7120,6 +7122,7 @@
method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
+ method public int getLeMaximumAdvertisingDataLength();
method public java.lang.String getName();
method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
method public int getProfileConnectionState(int);
@@ -10670,6 +10673,7 @@
field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
+ field public static final java.lang.String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
@@ -12755,7 +12759,7 @@
}
public class ColorFilter {
- ctor public ColorFilter();
+ ctor public deprecated ColorFilter();
}
public class ColorMatrix {
@@ -12779,6 +12783,9 @@
public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
ctor public ColorMatrixColorFilter(float[]);
+ method public void getColorMatrix(android.graphics.ColorMatrix);
+ method public void setColorMatrix(android.graphics.ColorMatrix);
+ method public void setColorMatrixArray(float[]);
}
public abstract class ColorSpace {
@@ -13002,6 +13009,10 @@
public class LightingColorFilter extends android.graphics.ColorFilter {
ctor public LightingColorFilter(int, int);
+ method public int getColorAdd();
+ method public int getColorMultiply();
+ method public void setColorAdd(int);
+ method public void setColorMultiply(int);
}
public class LinearGradient extends android.graphics.Shader {
@@ -13518,6 +13529,10 @@
public class PorterDuffColorFilter extends android.graphics.ColorFilter {
ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
+ method public int getColor();
+ method public android.graphics.PorterDuff.Mode getMode();
+ method public void setColor(int);
+ method public void setMode(android.graphics.PorterDuff.Mode);
}
public class PorterDuffXfermode extends android.graphics.Xfermode {
@@ -45073,8 +45088,8 @@
method public void addTouchables(java.util.ArrayList<android.view.View>);
method public android.view.ViewPropertyAnimator animate();
method public void announceForAccessibility(java.lang.CharSequence);
- method public void autofill(android.view.autofill.AutofillValue);
- method public void autofillVirtual(int, android.view.autofill.AutofillValue);
+ method public boolean autofill(android.view.autofill.AutofillValue);
+ method public boolean autofillVirtual(int, android.view.autofill.AutofillValue);
method protected boolean awakenScrollBars();
method protected boolean awakenScrollBars(int);
method protected boolean awakenScrollBars(int, boolean);
@@ -47590,6 +47605,7 @@
method public void onAutofillEventVirtual(android.view.View, int, int);
field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
+ field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
}
public final class AutofillValue implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index eb5ebd7..7fc18d0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5751,12 +5751,14 @@
method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>);
method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>);
method public void deleteNotificationChannel(java.lang.String);
+ method public void deleteNotificationChannelGroup(java.lang.String);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
method public int getImportance();
method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
+ method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
@@ -7589,6 +7591,7 @@
method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
+ method public int getLeMaximumAdvertisingDataLength();
method public java.lang.String getName();
method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
method public int getProfileConnectionState(int);
@@ -11328,6 +11331,7 @@
field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
+ field public static final java.lang.String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
@@ -13489,7 +13493,7 @@
}
public class ColorFilter {
- ctor public ColorFilter();
+ ctor public deprecated ColorFilter();
}
public class ColorMatrix {
@@ -13513,6 +13517,9 @@
public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
ctor public ColorMatrixColorFilter(float[]);
+ method public void getColorMatrix(android.graphics.ColorMatrix);
+ method public void setColorMatrix(android.graphics.ColorMatrix);
+ method public void setColorMatrixArray(float[]);
}
public abstract class ColorSpace {
@@ -13736,6 +13743,10 @@
public class LightingColorFilter extends android.graphics.ColorFilter {
ctor public LightingColorFilter(int, int);
+ method public int getColorAdd();
+ method public int getColorMultiply();
+ method public void setColorAdd(int);
+ method public void setColorMultiply(int);
}
public class LinearGradient extends android.graphics.Shader {
@@ -14252,6 +14263,10 @@
public class PorterDuffColorFilter extends android.graphics.ColorFilter {
ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
+ method public int getColor();
+ method public android.graphics.PorterDuff.Mode getMode();
+ method public void setColor(int);
+ method public void setMode(android.graphics.PorterDuff.Mode);
}
public class PorterDuffXfermode extends android.graphics.Xfermode {
@@ -48536,8 +48551,8 @@
method public void addTouchables(java.util.ArrayList<android.view.View>);
method public android.view.ViewPropertyAnimator animate();
method public void announceForAccessibility(java.lang.CharSequence);
- method public void autofill(android.view.autofill.AutofillValue);
- method public void autofillVirtual(int, android.view.autofill.AutofillValue);
+ method public boolean autofill(android.view.autofill.AutofillValue);
+ method public boolean autofillVirtual(int, android.view.autofill.AutofillValue);
method protected boolean awakenScrollBars();
method protected boolean awakenScrollBars(int);
method protected boolean awakenScrollBars(int, boolean);
@@ -51056,6 +51071,7 @@
method public void onAutofillEventVirtual(android.view.View, int, int);
field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
+ field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
}
public final class AutofillValue implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 3b02916..6702170 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5558,6 +5558,7 @@
method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>);
method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>);
method public void deleteNotificationChannel(java.lang.String);
+ method public void deleteNotificationChannelGroup(java.lang.String);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
@@ -5565,6 +5566,7 @@
method public android.content.ComponentName getEffectsSuppressor();
method public int getImportance();
method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
+ method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
@@ -7147,6 +7149,7 @@
method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
+ method public int getLeMaximumAdvertisingDataLength();
method public java.lang.String getName();
method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
method public int getProfileConnectionState(int);
@@ -10706,6 +10709,7 @@
field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
+ field public static final java.lang.String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
@@ -12793,7 +12797,7 @@
}
public class ColorFilter {
- ctor public ColorFilter();
+ ctor public deprecated ColorFilter();
}
public class ColorMatrix {
@@ -12817,6 +12821,9 @@
public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
ctor public ColorMatrixColorFilter(float[]);
+ method public void getColorMatrix(android.graphics.ColorMatrix);
+ method public void setColorMatrix(android.graphics.ColorMatrix);
+ method public void setColorMatrixArray(float[]);
}
public abstract class ColorSpace {
@@ -13040,6 +13047,10 @@
public class LightingColorFilter extends android.graphics.ColorFilter {
ctor public LightingColorFilter(int, int);
+ method public int getColorAdd();
+ method public int getColorMultiply();
+ method public void setColorAdd(int);
+ method public void setColorMultiply(int);
}
public class LinearGradient extends android.graphics.Shader {
@@ -13556,6 +13567,10 @@
public class PorterDuffColorFilter extends android.graphics.ColorFilter {
ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
+ method public int getColor();
+ method public android.graphics.PorterDuff.Mode getMode();
+ method public void setColor(int);
+ method public void setMode(android.graphics.PorterDuff.Mode);
}
public class PorterDuffXfermode extends android.graphics.Xfermode {
@@ -45433,8 +45448,8 @@
method public void addTouchables(java.util.ArrayList<android.view.View>);
method public android.view.ViewPropertyAnimator animate();
method public void announceForAccessibility(java.lang.CharSequence);
- method public void autofill(android.view.autofill.AutofillValue);
- method public void autofillVirtual(int, android.view.autofill.AutofillValue);
+ method public boolean autofill(android.view.autofill.AutofillValue);
+ method public boolean autofillVirtual(int, android.view.autofill.AutofillValue);
method protected boolean awakenScrollBars();
method protected boolean awakenScrollBars(int);
method protected boolean awakenScrollBars(int, boolean);
@@ -47959,6 +47974,7 @@
method public void onAutofillEventVirtual(android.view.View, int, int);
field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
+ field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
}
public final class AutofillValue implements android.os.Parcelable {
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index e5df278..75d4f32 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -21,8 +21,11 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
import android.annotation.Size;
import android.annotation.SystemApi;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.BroadcastBehavior;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -335,6 +338,8 @@
*
* @deprecated use #addOnAccountsUpdatedListener to get account updates in runtime.
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(includeBackground = true)
public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
"android.accounts.LOGIN_ACCOUNTS_CHANGED";
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 86adbb0..5c7a12c 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -431,31 +431,28 @@
// Force all the animations to end when the duration scale is 0.
private void forceToEnd() {
- if (mEndCanBeCalled) {
- end();
+ // TODO: Below is commented out to temp work around b/36241584, uncomment this when it's
+ // fixed.
+// if (mEndCanBeCalled) {
+// end();
+// return;
+// }
+
+ // Note: we don't want to combine this case with the end() method below because in
+ // the case of developer calling end(), we still need to make sure end() is explicitly
+ // called on the child animators to maintain the old behavior.
+ if (mReversing) {
+ handleAnimationEvents(mLastEventId, 0, getTotalDuration());
} else {
- // Note: we don't want to combine this case with the end() method below because in
- // the case of developer calling end(), we still need to make sure end() is explicitly
- // called on the child animators to maintain the old behavior.
- if (mReversing) {
- mLastEventId = mLastEventId == -1 ? mEvents.size() : mLastEventId;
- for (int j = mLastEventId - 1; j >= 0; j--) {
- AnimationEvent event = mEvents.get(j);
- if (event.mEvent == AnimationEvent.ANIMATION_END) {
- event.mNode.mAnimation.reverse();
- }
- }
- } else {
- for (int j = mLastEventId + 1; j < mEvents.size(); j++) {
- AnimationEvent event = mEvents.get(j);
- if (event.mEvent == AnimationEvent.ANIMATION_START) {
- event.mNode.mAnimation.start();
- }
- }
+ long zeroScalePlayTime = getTotalDuration();
+ if (zeroScalePlayTime == DURATION_INFINITE) {
+ // Use a large number for the play time.
+ zeroScalePlayTime = Integer.MAX_VALUE;
}
- mPlayingSet.clear();
- endAnimation();
+ handleAnimationEvents(mLastEventId, mEvents.size() - 1, zeroScalePlayTime);
}
+ mPlayingSet.clear();
+ endAnimation();
}
/**
@@ -730,7 +727,7 @@
if (isEmptySet) {
// In the case of empty AnimatorSet, or 0 duration scale, we will trigger the
// onAnimationEnd() right away.
- forceToEnd();
+ end();
}
}
@@ -1130,8 +1127,10 @@
*/
private void pulseFrame(Node node, long animPlayTime) {
if (!node.mEnded) {
+ float durationScale = ValueAnimator.getDurationScale();
+ durationScale = durationScale == 0 ? 1 : durationScale;
node.mEnded = node.mAnimation.pulseAnimationFrame(
- (long) (animPlayTime * ValueAnimator.getDurationScale()));
+ (long) (animPlayTime * durationScale));
}
}
diff --git a/core/java/android/annotation/BroadcastBehavior.java b/core/java/android/annotation/BroadcastBehavior.java
new file mode 100644
index 0000000..9b2ca31
--- /dev/null
+++ b/core/java/android/annotation/BroadcastBehavior.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.annotation;
+
+import android.content.Intent;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Description of how the annotated broadcast action behaves.
+ *
+ * @hide
+ */
+@Target({ ElementType.FIELD })
+@Retention(RetentionPolicy.SOURCE)
+public @interface BroadcastBehavior {
+ /**
+ * This broadcast will only be delivered to an explicit target.
+ *
+ * @see Intent#setPackage(String)
+ * @see Intent#setComponent(android.content.ComponentName)
+ */
+ boolean explicitOnly() default false;
+
+ /**
+ * This broadcast will only be delivered to registered receivers.
+ *
+ * @see Intent#FLAG_RECEIVER_REGISTERED_ONLY
+ */
+ boolean registeredOnly() default false;
+
+ /**
+ * This broadcast will include all {@code AndroidManifest.xml} receivers
+ * regardless of process state.
+ *
+ * @see Intent#FLAG_RECEIVER_INCLUDE_BACKGROUND
+ */
+ boolean includeBackground() default false;
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 78c29e8..e65c7c8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,6 +16,7 @@
package android.app;
+import android.metrics.LogMaker;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
@@ -23,6 +24,8 @@
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.policy.PhoneWindow;
import android.annotation.CallSuper;
@@ -765,6 +768,7 @@
/*package*/ Configuration mCurrentConfig;
private SearchManager mSearchManager;
private MenuInflater mMenuInflater;
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
static final class NonConfigurationInstances {
Object activity;
@@ -7188,6 +7192,8 @@
public void autofill(List<AutofillId> ids, List<AutofillValue> values) {
final View root = getWindow().getDecorView();
final int itemCount = ids.size();
+ int numApplied = 0;
+
for (int i = 0; i < itemCount; i++) {
final AutofillId id = ids.get(i);
final AutofillValue value = values.get(i);
@@ -7197,12 +7203,22 @@
Log.w(TAG, "autofill(): no View with id " + viewId);
continue;
}
+ final boolean wasApplied;
if (id.isVirtual()) {
- view.autofillVirtual(id.getVirtualChildId(), value);
+ wasApplied = view.autofillVirtual(id.getVirtualChildId(), value);
} else {
- view.autofill(value);
+ wasApplied = view.autofill(value);
+ }
+
+ if (wasApplied) {
+ numApplied++;
}
}
+
+ LogMaker log = new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_DATASET_APPLIED);
+ log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount);
+ log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, numApplied);
+ mMetricsLogger.write(log);
}
/** @hide */
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5cdfb8e..39b9d66 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -149,6 +149,7 @@
import libcore.io.EventLogger;
import libcore.io.IoUtils;
import libcore.net.event.NetworkEventDispatcher;
+import dalvik.system.BaseDexClassLoader;
import dalvik.system.CloseGuard;
import dalvik.system.VMDebug;
import dalvik.system.VMRuntime;
@@ -5571,6 +5572,16 @@
}
}
+ // If we use profiles, setup the dex reporter to notify package manager
+ // of any relevant dex loads. The idle maintenance job will use the information
+ // reported to optimize the loaded dex files.
+ // Note that we only need one global reporter per app.
+ // Make sure we do this before calling onCreate so that we can capture the
+ // complete application startup.
+ if (SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
+ BaseDexClassLoader.setReporter(DexLoadReporter.getInstance());
+ }
+
// Install the Network Security Config Provider. This must happen before the application
// code is loaded to prevent issues with instances of TLS objects being created before
// the provider is installed.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 0f2ce3c..09e7595 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -362,6 +362,8 @@
public static final String OPSTR_ANSWER_PHONE_CALLS
= "android:answer_phone_calls";
+ // Warning: If an permission is added here it also has to be added to
+ // com.android.packageinstaller.permission.utils.EventLogger
private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
// RUNTIME PERMISSIONS
// Contacts
diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java
new file mode 100644
index 0000000..13f288a
--- /dev/null
+++ b/core/java/android/app/DexLoadReporter.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.os.FileUtils;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import dalvik.system.BaseDexClassLoader;
+import dalvik.system.VMRuntime;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A dex load reporter which will notify package manager of any dex file loaded
+ * with {@code BaseDexClassLoader}.
+ * The goals are:
+ * 1) discover secondary dex files so that they can be optimized during the
+ * idle maintenance job.
+ * 2) determine whether or not a dex file is used by an app which does not
+ * own it (in order to select the optimal compilation method).
+ * @hide
+ */
+/*package*/ class DexLoadReporter implements BaseDexClassLoader.Reporter {
+ private static final String TAG = "DexLoadReporter";
+
+ private static final DexLoadReporter INSTANCE = new DexLoadReporter();
+
+ private static final boolean DEBUG = false;
+
+ // We must guard the access to the list of data directories because
+ // we might have concurrent accesses. Apps might load dex files while
+ // new data dirs are registered (due to creation of LoadedApks via
+ // create createApplicationContext).
+ @GuardedBy("mDataDirs")
+ private final Set<String> mDataDirs;
+
+ private DexLoadReporter() {
+ mDataDirs = new HashSet<>();
+ }
+
+ /*package*/ static DexLoadReporter getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Register an application data directory with the reporter.
+ * The data directories are used to determine if a dex file is secondary dex or not.
+ * Note that this method may be called multiple times for the same app, registering
+ * different data directories. This may happen when apps share the same user id
+ * ({@code android:sharedUserId}). For example, if app1 and app2 share the same user
+ * id, and app1 loads app2 apk, then both data directories will be registered.
+ */
+ /*package*/ void registerAppDataDir(String packageName, String dataDir) {
+ if (DEBUG) {
+ Slog.i(TAG, "Package " + packageName + " registering data dir: " + dataDir);
+ }
+ // TODO(calin): A few code paths imply that the data dir
+ // might be null. Investigate when that can happen.
+ if (dataDir != null) {
+ synchronized (mDataDirs) {
+ mDataDirs.add(dataDir);
+ }
+ }
+ }
+
+ @Override
+ public void report(List<String> dexPaths) {
+ if (dexPaths.isEmpty()) {
+ return;
+ }
+ // Notify the package manager about the dex loads unconditionally.
+ // The load might be for either a primary or secondary dex file.
+ notifyPackageManager(dexPaths);
+ // Check for secondary dex files and register them for profiling if
+ // possible.
+ registerSecondaryDexForProfiling(dexPaths);
+ }
+
+ private void notifyPackageManager(List<String> dexPaths) {
+ String packageName = ActivityThread.currentPackageName();
+ try {
+ ActivityThread.getPackageManager().notifyDexLoad(
+ packageName, dexPaths, VMRuntime.getRuntime().vmInstructionSet());
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re);
+ }
+ }
+
+ private void registerSecondaryDexForProfiling(List<String> dexPaths) {
+ if (!SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) {
+ return;
+ }
+ // Make a copy of the current data directories so that we don't keep the lock
+ // while registering for profiling. The registration will perform I/O to
+ // check for or create the profile.
+ String[] dataDirs;
+ synchronized (mDataDirs) {
+ dataDirs = mDataDirs.toArray(new String[0]);
+ }
+ for (String dexPath : dexPaths) {
+ registerSecondaryDexForProfiling(dexPath, dataDirs);
+ }
+ }
+
+ private void registerSecondaryDexForProfiling(String dexPath, String[] dataDirs) {
+ if (!isSecondaryDexFile(dexPath, dataDirs)) {
+ // The dex path is not a secondary dex file. Nothing to do.
+ return;
+ }
+ File secondaryProfile = getSecondaryProfileFile(dexPath);
+ try {
+ // Create the profile if not already there.
+ // Returns true if the file was created, false if the file already exists.
+ // or throws exceptions in case of errors.
+ boolean created = secondaryProfile.createNewFile();
+ if (DEBUG && created) {
+ Slog.i(TAG, "Created profile for secondary dex: " + secondaryProfile);
+ }
+ } catch (IOException ex) {
+ Slog.e(TAG, "Failed to create profile for secondary dex " + secondaryProfile +
+ ":" + ex.getMessage());
+ // Don't move forward with the registration if we failed to create the profile.
+ return;
+ }
+
+ VMRuntime.registerAppInfo(secondaryProfile.getPath(), new String[] { dexPath });
+ }
+
+ // A dex file is a secondary dex file if it is in any of the registered app
+ // data directories.
+ private boolean isSecondaryDexFile(String dexPath, String[] dataDirs) {
+ for (String dataDir : dataDirs) {
+ if (FileUtils.contains(dataDir, dexPath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Secondary dex profiles are stored next to the dex file and have the same
+ // name with '.prof' appended.
+ // NOTE: Keep in sync with installd.
+ private File getSecondaryProfileFile(String dexPath) {
+ return new File(dexPath + ".prof");
+ }
+}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 896f56c..5ea2480 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -67,6 +67,8 @@
ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
int getDeletedChannelCount(String pkg, int uid);
+ void deleteNotificationChannelGroup(String pkg, String channelGroupId);
+ ParceledListSlice getNotificationChannelGroups(String pkg);
// TODO: Remove this when callers have been migrated to the equivalent
// INotificationListener method.
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 77c4c7e..cf41e4e 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -55,7 +55,6 @@
import com.android.internal.util.ArrayUtils;
-import dalvik.system.BaseDexClassLoader;
import dalvik.system.VMRuntime;
import java.io.File;
@@ -752,39 +751,10 @@
VMRuntime.registerAppInfo(profileFile.getPath(),
codePaths.toArray(new String[codePaths.size()]));
- // Setup the reporter to notify package manager of any relevant dex loads.
- // At this point the primary apk is loaded and will not be reported.
- // Anything loaded from now on will be tracked as a potential secondary
- // or foreign dex file. The goal is to enable:
- // 1) monitoring and compilation of secondary dex file
- // 2) track whether or not a dex file is used by other apps (used to
- // determined the compilation filter of apks).
- if (BaseDexClassLoader.getReporter() != DexLoadReporter.INSTANCE) {
- // Set the dex load reporter if not already set.
- // Note that during the app's life cycle different LoadedApks may be
- // created and loaded (e.g. if two different apps share the same runtime).
- BaseDexClassLoader.setReporter(DexLoadReporter.INSTANCE);
- }
- }
-
- private static class DexLoadReporter implements BaseDexClassLoader.Reporter {
- private static final DexLoadReporter INSTANCE = new DexLoadReporter();
-
- private DexLoadReporter() {}
-
- @Override
- public void report(List<String> dexPaths) {
- if (dexPaths.isEmpty()) {
- return;
- }
- String packageName = ActivityThread.currentPackageName();
- try {
- ActivityThread.getPackageManager().notifyDexLoad(
- packageName, dexPaths, VMRuntime.getRuntime().vmInstructionSet());
- } catch (RemoteException re) {
- Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re);
- }
- }
+ // Register the app data directory with the reporter. It will
+ // help deciding whether or not a dex file is the primary apk or a
+ // secondary dex.
+ DexLoadReporter.getInstance().registerAppDataDir(mPackageName, mDataDir);
}
/**
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 2a78b6b..0379970 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -498,6 +498,30 @@
}
/**
+ * Returns all notification channel groups belonging to the calling app.
+ */
+ public List<NotificationChannelGroup> getNotificationChannelGroups() {
+ INotificationManager service = getService();
+ try {
+ return service.getNotificationChannelGroups(mContext.getPackageName()).getList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Deletes the given notification channel group.
+ */
+ public void deleteNotificationChannelGroup(String groupId) {
+ INotificationManager service = getService();
+ try {
+ service.deleteNotificationChannelGroup(mContext.getPackageName(), groupId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @hide
*/
@TestApi
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 0fb5966..d9b6eed 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -17,6 +17,7 @@
package android.app.admin;
import android.accounts.AccountManager;
+import android.annotation.BroadcastBehavior;
import android.annotation.IntDef;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -81,6 +82,7 @@
* that other applications can not abuse it.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_DEVICE_ADMIN_ENABLED
= "android.app.action.DEVICE_ADMIN_ENABLED";
@@ -94,6 +96,7 @@
* to the user before they disable your admin.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED
= "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
@@ -115,6 +118,7 @@
* its intent filter.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_DEVICE_ADMIN_DISABLED
= "android.app.action.DEVICE_ADMIN_DISABLED";
@@ -131,6 +135,7 @@
* this broadcast.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_PASSWORD_CHANGED
= "android.app.action.ACTION_PASSWORD_CHANGED";
@@ -147,6 +152,7 @@
* this broadcast.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_PASSWORD_FAILED
= "android.app.action.ACTION_PASSWORD_FAILED";
@@ -160,6 +166,7 @@
* this broadcast.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_PASSWORD_SUCCEEDED
= "android.app.action.ACTION_PASSWORD_SUCCEEDED";
@@ -173,6 +180,7 @@
* this broadcast.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_PASSWORD_EXPIRING
= "android.app.action.ACTION_PASSWORD_EXPIRING";
@@ -187,6 +195,7 @@
* @see DevicePolicyManager#isLockTaskPermitted(String)
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_LOCK_TASK_ENTERING
= "android.app.action.LOCK_TASK_ENTERING";
@@ -200,6 +209,7 @@
* @see DevicePolicyManager#isLockTaskPermitted(String)
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_LOCK_TASK_EXITING
= "android.app.action.LOCK_TASK_EXITING";
@@ -232,6 +242,7 @@
* <p>Output: Nothing</p>
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_PROFILE_PROVISIONING_COMPLETE =
"android.app.action.PROFILE_PROVISIONING_COMPLETE";
@@ -244,6 +255,7 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_BUGREPORT_SHARING_DECLINED =
"android.app.action.BUGREPORT_SHARING_DECLINED";
@@ -256,6 +268,7 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_BUGREPORT_FAILED = "android.app.action.BUGREPORT_FAILED";
/**
@@ -266,6 +279,7 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_BUGREPORT_SHARE =
"android.app.action.BUGREPORT_SHARE";
@@ -274,6 +288,7 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_SECURITY_LOGS_AVAILABLE
= "android.app.action.SECURITY_LOGS_AVAILABLE";
@@ -283,6 +298,7 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_NETWORK_LOGS_AVAILABLE
= "android.app.action.NETWORK_LOGS_AVAILABLE";
@@ -314,7 +330,8 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_USER_ADDED = "android.app.action.USER_ADDED";
+ @BroadcastBehavior(explicitOnly = true)
+ public static final String ACTION_USER_ADDED = "android.app.action.USER_ADDED";
/**
* Broadcast action: notify the device owner that a user or profile has been removed.
@@ -323,6 +340,7 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_USER_REMOVED = "android.app.action.USER_REMOVED";
/**
@@ -401,6 +419,7 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_NOTIFY_PENDING_SYSTEM_UPDATE =
"android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE";
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 67c791d..74a39e8 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -16,8 +16,11 @@
package android.appwidget;
+import android.annotation.BroadcastBehavior;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -81,12 +84,14 @@
*
* @see #ACTION_APPWIDGET_CONFIGURE
*/
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
/**
* Similar to ACTION_APPWIDGET_PICK, but used from keyguard
* @hide
*/
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String
ACTION_KEYGUARD_APPWIDGET_PICK = "android.appwidget.action.KEYGUARD_APPWIDGET_PICK";
@@ -133,6 +138,7 @@
* @see #ACTION_APPWIDGET_CONFIGURE
*
*/
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_APPWIDGET_BIND = "android.appwidget.action.APPWIDGET_BIND";
/**
@@ -157,6 +163,7 @@
* and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED}
* broadcast.
*/
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
/**
@@ -290,6 +297,8 @@
*
* @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
/**
@@ -302,6 +311,8 @@
* AppWidgetProvider.onAppWidgetOptionsChanged(Context context,
* AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras)
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS";
/**
@@ -312,6 +323,8 @@
*
* @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds)
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
/**
@@ -322,6 +335,8 @@
*
* @see AppWidgetProvider#onEnabled AppWidgetProvider.onDisabled(Context context)
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
/**
@@ -334,6 +349,8 @@
*
* @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
/**
@@ -365,6 +382,8 @@
*
* @see #ACTION_APPWIDGET_HOST_RESTORED
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_APPWIDGET_RESTORED
= "android.appwidget.action.APPWIDGET_RESTORED";
@@ -402,6 +421,8 @@
*
* @see #ACTION_APPWIDGET_RESTORED
*/
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(explicitOnly = true)
public static final String ACTION_APPWIDGET_HOST_RESTORED
= "android.appwidget.action.APPWIDGET_HOST_RESTORED";
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 488511b..4e1e42d 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1483,6 +1483,25 @@
}
/**
+ * Return the maximum LE advertising data length,
+ * if LE Extended Advertising feature is supported.
+ *
+ * @return the maximum LE advertising data length.
+ */
+ public int getLeMaximumAdvertisingDataLength() {
+ if (!getLeAccess()) return 0;
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) return mService.getLeMaximumAdvertisingDataLength();
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to get getLeMaximumAdvertisingDataLength, error: ", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return 0;
+ }
+
+ /**
* Return true if hardware has entries available for matching beacons
*
* @return true if there are hw entries available for matching beacons
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 76ca554..b337817 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -108,6 +108,7 @@
boolean isLeCodedPhySupported();
boolean isLeExtendedAdvertisingSupported();
boolean isLePeriodicAdvertisingSupported();
+ int getLeMaximumAdvertisingDataLength();
BluetoothActivityEnergyInfo reportActivityInfo();
/**
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 33fedc7..29f29e7 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -50,14 +50,6 @@
void stopScan(in int scannerId);
void flushPendingBatchResults(in int scannerId);
- void registerAdvertiser(in IAdvertiserCallback callback);
- void unregisterAdvertiser(in int advertiserId);
- void startMultiAdvertising(in int advertiserId,
- in AdvertiseData advertiseData,
- in AdvertiseData scanResponse,
- in AdvertiseSettings settings);
- void stopMultiAdvertising(in int advertiserId);
-
void startAdvertisingSet(in AdvertisingSetParameters parameters, in AdvertiseData advertiseData,
in AdvertiseData scanResponse, in PeriodicAdvertisingParameters periodicParameters,
in AdvertiseData periodicData, in IAdvertisingSetCallback callback);
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index e03c947..c9f1d7a 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -28,6 +28,7 @@
import android.os.RemoteException;
import android.util.Log;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@@ -60,11 +61,12 @@
private final IBluetoothManager mBluetoothManager;
private final Handler mHandler;
private BluetoothAdapter mBluetoothAdapter;
- private final Map<AdvertiseCallback, AdvertiseCallbackWrapper>
- mLeAdvertisers = new HashMap<AdvertiseCallback, AdvertiseCallbackWrapper>();
+ private final Map<AdvertiseCallback, AdvertisingSetCallback>
+ mLegacyAdvertisers = new HashMap<>();
private final Map<AdvertisingSetCallback, IAdvertisingSetCallback>
- advertisingSetCallbackWrappers = new HashMap<>();
- private final Map<Integer, AdvertisingSet> advertisingSets = new HashMap<>();
+ mCallbackWrappers = Collections.synchronizedMap(new HashMap<>());
+ private final Map<Integer, AdvertisingSet>
+ mAdvertisingSets = Collections.synchronizedMap(new HashMap<>());
/**
* Use BluetoothAdapter.getLeAdvertiser() instead.
@@ -109,7 +111,7 @@
public void startAdvertising(AdvertiseSettings settings,
AdvertiseData advertiseData, AdvertiseData scanResponse,
final AdvertiseCallback callback) {
- synchronized (mLeAdvertisers) {
+ synchronized (mLegacyAdvertisers) {
BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
@@ -120,25 +122,65 @@
postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE);
return;
}
- if (mLeAdvertisers.containsKey(callback)) {
+ if (mLegacyAdvertisers.containsKey(callback)) {
postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);
return;
}
- IBluetoothGatt gatt;
- try {
- gatt = mBluetoothManager.getBluetoothGatt();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
- postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
- return;
+ AdvertisingSetParameters.Builder parameters = new AdvertisingSetParameters.Builder();
+ parameters.setLegacyMode(true);
+ parameters.setConnectable(isConnectable);
+ parameters.setTimeout(settings.getTimeout());
+ if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_POWER) {
+ parameters.setInterval(1600); // 1s
+ } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_BALANCED) {
+ parameters.setInterval(400); // 250ms
+ } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) {
+ parameters.setInterval(160); // 100ms
}
- AdvertiseCallbackWrapper wrapper = new AdvertiseCallbackWrapper(callback, advertiseData,
- scanResponse, settings, gatt);
- wrapper.startRegisteration();
+
+ if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW) {
+ parameters.setTxPowerLevel(-21);
+ } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_LOW) {
+ parameters.setTxPowerLevel(-15);
+ } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) {
+ parameters.setTxPowerLevel(-7);
+ } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) {
+ parameters.setTxPowerLevel(1);
+ }
+
+ AdvertisingSetCallback wrapped = wrapOldCallback(callback, settings);
+ mLegacyAdvertisers.put(callback, wrapped);
+ startAdvertisingSet(parameters.build(), advertiseData, scanResponse, null, null,
+ wrapped);
}
}
+ AdvertisingSetCallback wrapOldCallback(AdvertiseCallback callback, AdvertiseSettings settings) {
+ return new AdvertisingSetCallback() {
+ public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int status) {
+ if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
+ postStartFailure(callback, status);
+ return;
+ }
+
+ postStartSuccess(callback, settings);
+ }
+
+ /* Legacy advertiser is disabled on timeout */
+ public void onAdvertisingEnabled(int advertiserId, boolean enabled, int status) {
+ if (enabled == true) {
+ Log.e(TAG, "Legacy advertiser should be only disabled on timeout," +
+ " but was enabled!");
+ return;
+ }
+
+ stopAdvertising(callback);
+ }
+
+ };
+ }
+
/**
* Stop Bluetooth LE advertising. The {@code callback} must be the same one use in
* {@link BluetoothLeAdvertiser#startAdvertising}.
@@ -148,20 +190,21 @@
* @param callback {@link AdvertiseCallback} identifies the advertising instance to stop.
*/
public void stopAdvertising(final AdvertiseCallback callback) {
- synchronized (mLeAdvertisers) {
+ synchronized (mLegacyAdvertisers) {
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
}
- AdvertiseCallbackWrapper wrapper = mLeAdvertisers.get(callback);
+ AdvertisingSetCallback wrapper = mLegacyAdvertisers.get(callback);
if (wrapper == null) return;
- wrapper.stopAdvertising();
+
+ stopAdvertisingSet(wrapper);
}
}
/**
* Creates a new advertising set. If operation succeed, device will start advertising. This
* method returns immediately, the operation status is delivered through
- * {@code callback.onNewAdvertisingSet()}.
+ * {@code callback.onAdvertisingSetStarted()}.
* <p>
* @param parameters advertising set parameters.
* @param advertiseData Advertisement data to be broadcasted.
@@ -180,7 +223,7 @@
/**
* Creates a new advertising set. If operation succeed, device will start advertising. This
* method returns immediately, the operation status is delivered through
- * {@code callback.onNewAdvertisingSet()}.
+ * {@code callback.onAdvertisingSetStarted()}.
* <p>
* @param parameters advertising set parameters.
* @param advertiseData Advertisement data to be broadcasted.
@@ -209,7 +252,10 @@
}
IAdvertisingSetCallback wrapped = wrap(callback, handler);
- advertisingSetCallbackWrappers.put(callback, wrapped);
+ if (mCallbackWrappers.putIfAbsent(callback, wrapped) != null) {
+ throw new IllegalArgumentException(
+ "callback instance already associated with advertising");
+ }
try {
gatt.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
@@ -229,10 +275,9 @@
throw new IllegalArgumentException("callback cannot be null");
}
- IAdvertisingSetCallback wrapped = advertisingSetCallbackWrappers.remove(callback);
+ IAdvertisingSetCallback wrapped = mCallbackWrappers.remove(callback);
if (wrapped == null) {
- throw new IllegalArgumentException(
- "callback does not represent valid registered callback.");
+ return;
}
IBluetoothGatt gatt;
@@ -251,7 +296,9 @@
* @hide
*/
public void cleanup() {
- mLeAdvertisers.clear();
+ mLegacyAdvertisers.clear();
+ mCallbackWrappers.clear();
+ mAdvertisingSets.clear();
}
// Compute the size of advertisement data or scan resp
@@ -317,13 +364,13 @@
public void run() {
if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
callback.onAdvertisingSetStarted(null, status);
- advertisingSetCallbackWrappers.remove(callback);
+ mCallbackWrappers.remove(callback);
return;
}
AdvertisingSet advertisingSet =
new AdvertisingSet(advertiserId, mBluetoothManager);
- advertisingSets.put(advertiserId, advertisingSet);
+ mAdvertisingSets.put(advertiserId, advertisingSet);
callback.onAdvertisingSetStarted(advertisingSet, status);
}
});
@@ -333,10 +380,10 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onAdvertisingSetStopped(advertisingSet);
- advertisingSets.remove(advertiserId);
- advertisingSetCallbackWrappers.remove(callback);
+ mAdvertisingSets.remove(advertiserId);
+ mCallbackWrappers.remove(callback);
}
});
}
@@ -345,7 +392,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onAdvertisingEnabled(advertisingSet, enabled, status);
}
});
@@ -355,7 +402,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onAdvertisingDataSet(advertisingSet, status);
}
});
@@ -365,7 +412,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onScanResponseDataSet(advertisingSet, status);
}
});
@@ -375,7 +422,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onAdvertisingParametersUpdated(advertisingSet, status);
}
});
@@ -385,7 +432,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onPeriodicAdvertisingParametersUpdated(advertisingSet, status);
}
});
@@ -395,7 +442,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onPeriodicAdvertisingDataSet(advertisingSet, status);
}
});
@@ -405,7 +452,7 @@
handler.post(new Runnable() {
@Override
public void run() {
- AdvertisingSet advertisingSet = advertisingSets.get(advertiserId);
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
callback.onPeriodicAdvertisingEnable(advertisingSet, enable, status);
}
});
@@ -413,144 +460,6 @@
};
}
- /**
- * Bluetooth GATT interface callbacks for advertising.
- */
- private class AdvertiseCallbackWrapper extends IAdvertiserCallback.Stub {
- private static final int LE_CALLBACK_TIMEOUT_MILLIS = 2000;
- private final AdvertiseCallback mAdvertiseCallback;
- private final AdvertiseData mAdvertisement;
- private final AdvertiseData mScanResponse;
- private final AdvertiseSettings mSettings;
- private final IBluetoothGatt mBluetoothGatt;
-
- // mAdvertiserId -1: not registered
- // -2: advertise stopped or registration timeout
- // >=0: registered and advertising started
- private int mAdvertiserId;
- private boolean mIsAdvertising = false;
- private int registrationError = AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR;
-
- public AdvertiseCallbackWrapper(AdvertiseCallback advertiseCallback,
- AdvertiseData advertiseData, AdvertiseData scanResponse,
- AdvertiseSettings settings,
- IBluetoothGatt bluetoothGatt) {
- mAdvertiseCallback = advertiseCallback;
- mAdvertisement = advertiseData;
- mScanResponse = scanResponse;
- mSettings = settings;
- mBluetoothGatt = bluetoothGatt;
- mAdvertiserId = -1;
- }
-
- public void startRegisteration() {
- synchronized (this) {
- if (mAdvertiserId == -2) return;
-
- try {
- mBluetoothGatt.registerAdvertiser(this);
- wait(LE_CALLBACK_TIMEOUT_MILLIS);
- } catch (InterruptedException | RemoteException e) {
- Log.e(TAG, "Failed to start registeration", e);
- }
- if (mAdvertiserId >= 0 && mIsAdvertising) {
- mLeAdvertisers.put(mAdvertiseCallback, this);
- } else if (mAdvertiserId < 0) {
-
- // Registration timeout, reset mClientIf to -2 so no subsequent operations can
- // proceed.
- if (mAdvertiserId == -1) mAdvertiserId = -2;
- // Post internal error if registration failed.
- postStartFailure(mAdvertiseCallback, registrationError);
- } else {
- // Unregister application if it's already registered but advertise failed.
- try {
- mBluetoothGatt.unregisterAdvertiser(mAdvertiserId);
- mAdvertiserId = -2;
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception when unregistering", e);
- }
- }
- }
- }
-
- public void stopAdvertising() {
- synchronized (this) {
- try {
- mBluetoothGatt.stopMultiAdvertising(mAdvertiserId);
- wait(LE_CALLBACK_TIMEOUT_MILLIS);
- } catch (InterruptedException | RemoteException e) {
- Log.e(TAG, "Failed to stop advertising", e);
- }
- // Advertise callback should have been removed from LeAdvertisers when
- // onMultiAdvertiseCallback was called. In case onMultiAdvertiseCallback is never
- // invoked and wait timeout expires, remove callback here.
- if (mLeAdvertisers.containsKey(mAdvertiseCallback)) {
- mLeAdvertisers.remove(mAdvertiseCallback);
- }
- }
- }
-
- /**
- * Advertiser interface registered - app is ready to go
- */
- @Override
- public void onAdvertiserRegistered(int status, int advertiserId) {
- Log.d(TAG, "onAdvertiserRegistered() - status=" + status + " advertiserId=" + advertiserId);
- synchronized (this) {
- if (status == BluetoothGatt.GATT_SUCCESS) {
- try {
- if (mAdvertiserId == -2) {
- // Registration succeeds after timeout, unregister advertiser.
- mBluetoothGatt.unregisterAdvertiser(advertiserId);
- } else {
- mAdvertiserId = advertiserId;
- mBluetoothGatt.startMultiAdvertising(mAdvertiserId, mAdvertisement,
- mScanResponse, mSettings);
- }
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "failed to start advertising", e);
- }
- } else if (status == AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS) {
- registrationError = status;
- }
- // Registration failed.
- mAdvertiserId = -2;
- notifyAll();
- }
- }
-
- @Override
- public void onMultiAdvertiseCallback(int status, boolean isStart,
- AdvertiseSettings settings) {
- synchronized (this) {
- if (isStart) {
- if (status == AdvertiseCallback.ADVERTISE_SUCCESS) {
- // Start success
- mIsAdvertising = true;
- postStartSuccess(mAdvertiseCallback, settings);
- } else {
- // Start failure.
- postStartFailure(mAdvertiseCallback, status);
- }
- } else {
- // unregister advertiser for stop.
- try {
- mBluetoothGatt.unregisterAdvertiser(mAdvertiserId);
- mAdvertiserId = -2;
- mIsAdvertising = false;
- mLeAdvertisers.remove(mAdvertiseCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception when unregistering", e);
- }
- }
- notifyAll();
- }
-
- }
- }
-
private void postStartFailure(final AdvertiseCallback callback, final int error) {
mHandler.post(new Runnable() {
@Override
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1f01e28..4dc6fd2 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -17,6 +17,7 @@
package android.content;
import android.annotation.AnyRes;
+import android.annotation.BroadcastBehavior;
import android.annotation.IntDef;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -1992,6 +1993,7 @@
* This is a protected intent that can only be sent by the system.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(includeBackground = true)
public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
/**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 33f57e0..10ffab2 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2355,6 +2355,13 @@
= "android.hardware.vr.high_performance";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device implements headtracking suitable for a VR device.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
+
+ /**
* Action to external storage service to clean out removed apps.
* @hide
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e15a0e2..5a28e87 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -211,6 +211,14 @@
CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
}
+ private static final boolean LOG_UNSAFE_BROADCASTS = false;
+
+ // Set of broadcast actions that are safe for manifest receivers
+ private static final Set<String> SAFE_BROADCASTS = new ArraySet<>();
+ static {
+ SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED);
+ }
+
/** @hide */
public static class NewPermissionInfo {
public final String name;
@@ -4247,6 +4255,18 @@
if (intent.isVisibleToInstantApp()) {
a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
}
+ if (LOG_UNSAFE_BROADCASTS && receiver
+ && (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O)) {
+ for (int i = 0; i < intent.countActions(); i++) {
+ final String action = intent.getAction(i);
+ if (action == null || !action.startsWith("android.")) continue;
+ if (!SAFE_BROADCASTS.contains(action)) {
+ Slog.w(TAG, "Broadcast " + action + " may never be delivered to "
+ + owner.packageName + " as requested at: "
+ + parser.getPositionDescription());
+ }
+ }
+ }
} else if (!receiver && parser.getName().equals("preferred")) {
ActivityIntentInfo intent = new ActivityIntentInfo(a);
if (!parseIntent(res, parser, false /*allowGlobs*/, false /*allowAutoVerify*/,
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 8bc65af..e3b97e8 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -100,6 +100,8 @@
private final CameraCharacteristics mCharacteristics;
private final int mTotalPartialCount;
+ private static final long NANO_PER_SECOND = 1000000000; //ns
+
/**
* A list tracking request and its expected last regular frame number and last reprocess frame
* number. Updated when calling ICameraDeviceUser methods.
@@ -1239,6 +1241,14 @@
private final List<CaptureRequest> mRequestList;
private final Handler mHandler;
private final int mSessionId;
+ /**
+ * <p>Determine if the callback holder is for a constrained high speed request list that
+ * expects batched capture results. Capture results will be batched if the request list
+ * is interleaved with preview and video requests. Capture results won't be batched if the
+ * request list only contains preview requests, or if the request doesn't belong to a
+ * constrained high speed list.
+ */
+ private final boolean mHasBatchedOutputs;
CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList,
Handler handler, boolean repeating, int sessionId) {
@@ -1251,6 +1261,25 @@
mRequestList = new ArrayList<CaptureRequest>(requestList);
mCallback = callback;
mSessionId = sessionId;
+
+ // Check whether this callback holder is for batched outputs.
+ // The logic here should match createHighSpeedRequestList.
+ boolean hasBatchedOutputs = true;
+ for (int i = 0; i < requestList.size(); i++) {
+ CaptureRequest request = requestList.get(i);
+ if (!request.isPartOfCRequestList()) {
+ hasBatchedOutputs = false;
+ break;
+ }
+ if (i == 0) {
+ Collection<Surface> targets = request.getTargets();
+ if (targets.size() != 2) {
+ hasBatchedOutputs = false;
+ break;
+ }
+ }
+ }
+ mHasBatchedOutputs = hasBatchedOutputs;
}
public boolean isRepeating() {
@@ -1288,6 +1317,14 @@
public int getSessionId() {
return mSessionId;
}
+
+ public int getRequestCount() {
+ return mRequestList.size();
+ }
+
+ public boolean hasBatchedOutputs() {
+ return mHasBatchedOutputs;
+ }
}
/**
@@ -1777,10 +1814,27 @@
@Override
public void run() {
if (!CameraDeviceImpl.this.isClosed()) {
- holder.getCallback().onCaptureStarted(
- CameraDeviceImpl.this,
- holder.getRequest(resultExtras.getSubsequenceId()),
- timestamp, frameNumber);
+ final int subsequenceId = resultExtras.getSubsequenceId();
+ final CaptureRequest request = holder.getRequest(subsequenceId);
+
+ if (holder.hasBatchedOutputs()) {
+ // Send derived onCaptureStarted for requests within the batch
+ final Range<Integer> fpsRange =
+ request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
+ for (int i = 0; i < holder.getRequestCount(); i++) {
+ holder.getCallback().onCaptureStarted(
+ CameraDeviceImpl.this,
+ holder.getRequest(i),
+ timestamp - (subsequenceId - i) *
+ NANO_PER_SECOND/fpsRange.getUpper(),
+ frameNumber - (subsequenceId - i));
+ }
+ } else {
+ holder.getCallback().onCaptureStarted(
+ CameraDeviceImpl.this,
+ holder.getRequest(resultExtras.getSubsequenceId()),
+ timestamp, frameNumber);
+ }
}
}
});
@@ -1845,46 +1899,91 @@
Runnable resultDispatch = null;
CaptureResult finalResult;
+ // Make a copy of the native metadata before it gets moved to a CaptureResult
+ // object.
+ final CameraMetadataNative resultCopy;
+ if (holder.hasBatchedOutputs()) {
+ resultCopy = new CameraMetadataNative(result);
+ } else {
+ resultCopy = null;
+ }
// Either send a partial result or the final capture completed result
if (isPartialResult) {
final CaptureResult resultAsCapture =
new CaptureResult(result, request, resultExtras);
-
// Partial result
resultDispatch = new Runnable() {
@Override
public void run() {
- if (!CameraDeviceImpl.this.isClosed()){
- holder.getCallback().onCaptureProgressed(
- CameraDeviceImpl.this,
- request,
- resultAsCapture);
+ if (!CameraDeviceImpl.this.isClosed()) {
+ if (holder.hasBatchedOutputs()) {
+ // Send derived onCaptureProgressed for requests within
+ // the batch.
+ for (int i = 0; i < holder.getRequestCount(); i++) {
+ CameraMetadataNative resultLocal =
+ new CameraMetadataNative(resultCopy);
+ CaptureResult resultInBatch = new CaptureResult(
+ resultLocal, holder.getRequest(i), resultExtras);
+
+ holder.getCallback().onCaptureProgressed(
+ CameraDeviceImpl.this,
+ holder.getRequest(i),
+ resultInBatch);
+ }
+ } else {
+ holder.getCallback().onCaptureProgressed(
+ CameraDeviceImpl.this,
+ request,
+ resultAsCapture);
+ }
}
}
};
-
finalResult = resultAsCapture;
} else {
List<CaptureResult> partialResults =
mFrameNumberTracker.popPartialResults(frameNumber);
+ final long sensorTimestamp =
+ result.get(CaptureResult.SENSOR_TIMESTAMP);
+ final Range<Integer> fpsRange =
+ request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
+ final int subsequenceId = resultExtras.getSubsequenceId();
final TotalCaptureResult resultAsCapture = new TotalCaptureResult(result,
request, resultExtras, partialResults, holder.getSessionId());
-
// Final capture result
resultDispatch = new Runnable() {
@Override
public void run() {
if (!CameraDeviceImpl.this.isClosed()){
- holder.getCallback().onCaptureCompleted(
- CameraDeviceImpl.this,
- request,
- resultAsCapture);
+ if (holder.hasBatchedOutputs()) {
+ // Send derived onCaptureCompleted for requests within
+ // the batch.
+ for (int i = 0; i < holder.getRequestCount(); i++) {
+ resultCopy.set(CaptureResult.SENSOR_TIMESTAMP,
+ sensorTimestamp - (subsequenceId - i) *
+ NANO_PER_SECOND/fpsRange.getUpper());
+ CameraMetadataNative resultLocal =
+ new CameraMetadataNative(resultCopy);
+ TotalCaptureResult resultInBatch = new TotalCaptureResult(
+ resultLocal, holder.getRequest(i), resultExtras,
+ partialResults, holder.getSessionId());
+
+ holder.getCallback().onCaptureCompleted(
+ CameraDeviceImpl.this,
+ holder.getRequest(i),
+ resultInBatch);
+ }
+ } else {
+ holder.getCallback().onCaptureCompleted(
+ CameraDeviceImpl.this,
+ request,
+ resultAsCapture);
+ }
}
}
};
-
finalResult = resultAsCapture;
}
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index a265dd0..94fd5b0 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -219,6 +219,7 @@
public native final void writeStatus(int status);
public native final void verifySuccess();
public native final void releaseTemporaryStorage();
+ public native final void release();
public native final void send();
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 6663f03..6213d27 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -215,8 +215,10 @@
* @throws IllegalArgumentException if {@code requiredIds} is {@code null} or empty.
*/
public Builder(@SaveDataType int type, @NonNull AutofillId[] requiredIds) {
+ if (false) {// TODO(b/33197203): re-move when clients use it
Preconditions.checkArgument(requiredIds != null && requiredIds.length > 0,
- "must have at least on required id: " + Arrays.toString(requiredIds));
+ "must have at least one required id: " + Arrays.toString(requiredIds));
+ }
switch (type) {
case SAVE_DATA_TYPE_PASSWORD:
case SAVE_DATA_TYPE_ADDRESS:
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index 10e4177..6034c18 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -50,5 +50,13 @@
* @param enabled true if the device should be placed in persistent VR mode.
*/
void setPersistentVrModeEnabled(in boolean enabled);
+
+ /**
+ * Return current virtual display id.
+ *
+ * @return {@link android.view.Display.INVALID_DISPLAY} if there is no virtual display
+ * currently, else return the display id of the virtual display
+ */
+ int getCompatibilityDisplayId();
}
diff --git a/core/java/android/util/LauncherIcons.java b/core/java/android/util/LauncherIcons.java
new file mode 100644
index 0000000..e5aa2b5
--- /dev/null
+++ b/core/java/android/util/LauncherIcons.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.util;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Utility class to handle icon treatments (e.g., shadow generation) for the Launcher icons.
+ * @hide
+ */
+public final class LauncherIcons {
+
+ private final Paint mPaint = new Paint();
+ private final Canvas mCanvas = new Canvas();
+
+ private static final int KEY_SHADOW_ALPHA = 61;
+ private static final int AMBIENT_SHADOW_ALPHA = 30;
+ private static final float BLUR_FACTOR = 0.5f / 48;
+ private int mShadowInset;
+ private Bitmap mShadowBitmap;
+ private int mIconSize;
+ private Resources mRes;
+
+ public LauncherIcons(Context context) {
+ mRes = context.getResources();
+ DisplayMetrics metrics = mRes.getDisplayMetrics();
+ mShadowInset = (int) metrics.density / DisplayMetrics.DENSITY_DEFAULT;
+ mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
+ Paint.FILTER_BITMAP_FLAG));
+ mIconSize = (int) mRes.getDimensionPixelSize(android.R.dimen.app_icon_size);
+ }
+
+ /**
+ * Draw the drawable into a bitmap.
+ */
+ public Bitmap createIconBitmap(Drawable icon) {
+ final Bitmap bitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ARGB_8888);
+ mPaint.setAlpha(255);
+ mCanvas.setBitmap(bitmap);
+ int iconInset = 0;
+ if (mShadowBitmap != null) {
+ mCanvas.drawBitmap(mShadowBitmap, 0, 0, mPaint);
+ iconInset = mShadowInset;
+ }
+
+ icon.setBounds(iconInset, iconInset, mIconSize - iconInset,
+ mIconSize - iconInset);
+ icon.draw(mCanvas);
+ mCanvas.setBitmap(null);
+ return bitmap;
+ }
+
+ public Drawable wrapIconDrawableWithShadow(Drawable drawable) {
+ if (!(drawable instanceof AdaptiveIconDrawable)) {
+ return drawable;
+ }
+ AdaptiveIconDrawable d =
+ (AdaptiveIconDrawable) drawable.getConstantState().newDrawable().mutate();
+ getShadowBitmap(d);
+ Bitmap iconbitmap = createIconBitmap(d);
+ return new BitmapDrawable(mRes, iconbitmap);
+ }
+
+ private Bitmap getShadowBitmap(AdaptiveIconDrawable d) {
+ if (mShadowBitmap != null) {
+ return mShadowBitmap;
+ }
+
+ int shadowSize = mIconSize - mShadowInset;
+ mShadowBitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ALPHA_8);
+ mCanvas.setBitmap(mShadowBitmap);
+
+ // Draw key shadow
+ mPaint.setColor(Color.TRANSPARENT);
+ float blur = BLUR_FACTOR * mIconSize;
+ mPaint.setShadowLayer(blur, 0, mShadowInset, KEY_SHADOW_ALPHA << 24);
+ d.setBounds(mShadowInset, mShadowInset, mIconSize - mShadowInset, mIconSize - mShadowInset);
+ mCanvas.drawPath(d.getIconMask(), mPaint);
+
+ // Draw ambient shadow
+ mPaint.setShadowLayer(blur, 0, 0, AMBIENT_SHADOW_ALPHA << 24);
+ d.setBounds(mShadowInset, 2 * mShadowInset, mIconSize - mShadowInset, mIconSize);
+ mCanvas.drawPath(d.getIconMask(), mPaint);
+ mPaint.clearShadowLayer();
+
+ return mShadowBitmap;
+ }
+}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 6d320ef..824e035 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,8 +16,9 @@
package android.view;
-import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
+import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER;
import android.content.Context;
@@ -28,6 +29,7 @@
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
@@ -777,6 +779,31 @@
}
/**
+ * This method still exists only for compatibility reasons because some applications have relied
+ * on this method via reflection. See Issue 36345857 for details.
+ *
+ * @deprecated No platform code is using this method anymore.
+ * @hide
+ */
+ @Deprecated
+ public void setWindowType(int type) {
+ if (getContext().getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.N_MR1) {
+ throw new UnsupportedOperationException(
+ "SurfaceView#setWindowType() has never been a public API.");
+ }
+
+ if (type == TYPE_APPLICATION_PANEL) {
+ Log.e(TAG, "If you are calling SurfaceView#setWindowType(TYPE_APPLICATION_PANEL) "
+ + "just to make the SurfaceView to be placed on top of its window, you must "
+ + "call setZOrderOnTop(true) instead.", new Throwable());
+ setZOrderOnTop(true);
+ return;
+ }
+ Log.e(TAG, "SurfaceView#setWindowType(int) is deprecated and now does nothing. "
+ + "type=" + type, new Throwable());
+ }
+
+ /**
* Check to see if the surface has fixed size dimensions or if the surface's
* dimensions are dimensions are dependent on its current layout.
*
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 80f6c32..6cddbac 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7445,8 +7445,11 @@
* </pre>
*
* @param value value to be autofilled.
+ *
+ * @return {@code true} if the view was successfully autofilled, {@code false} otherwise
*/
- public void autofill(@SuppressWarnings("unused") AutofillValue value) {
+ public boolean autofill(@SuppressWarnings("unused") AutofillValue value) {
+ return false;
}
/**
@@ -7457,9 +7460,12 @@
*
* @param value value to be autofilled.
* @param virtualId id identifying the virtual child inside the custom view.
+ *
+ * @return {@code true} if the view was successfully autofilled, {@code false} otherwise
*/
- public void autofillVirtual(@SuppressWarnings("unused") int virtualId,
+ public boolean autofillVirtual(@SuppressWarnings("unused") int virtualId,
@SuppressWarnings("unused") AutofillValue value) {
+ return false;
}
/**
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index f036b9c..b852aab 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -83,7 +83,7 @@
/** @hide */ public static final int FLAG_VIEW_EXITED = 0x20000000;
/** @hide */ public static final int FLAG_VALUE_CHANGED = 0x10000000;
- private final Rect mTempRect = new Rect();
+ @NonNull private final Rect mTempRect = new Rect();
private final IAutoFillManager mService;
private IAutoFillManagerClient mServiceClient;
@@ -196,6 +196,9 @@
ensureServiceClientAddedIfNeeded();
if (!mEnabled) {
+ if (mCallback != null) {
+ mCallback.onAutofillEvent(view, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
+ }
return;
}
@@ -241,6 +244,10 @@
ensureServiceClientAddedIfNeeded();
if (!mEnabled) {
+ if (mCallback != null) {
+ mCallback.onAutofillEventVirtual(view, childId,
+ AutofillCallback.EVENT_INPUT_UNAVAILABLE);
+ }
return;
}
@@ -371,8 +378,8 @@
return new AutofillId(parent.getAccessibilityViewId(), childId);
}
- private void startSession(AutofillId id, IBinder windowToken, Rect bounds,
- AutofillValue value, int flags) {
+ private void startSession(@NonNull AutofillId id, @NonNull IBinder windowToken,
+ @NonNull Rect bounds, @NonNull AutofillValue value, int flags) {
if (DEBUG) {
Log.d(TAG, "startSession(): id=" + id + ", bounds=" + bounds + ", value=" + value
+ ", flags=" + flags);
@@ -381,8 +388,8 @@
try {
mService.startSession(mContext.getActivityToken(), windowToken,
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
- mCallback != null, flags);
- final AutofillClient client = getClient();
+ mCallback != null, flags, mContext.getOpPackageName());
+ AutofillClient client = getClient();
if (client != null) {
client.resetableStateAvailable();
}
@@ -539,6 +546,15 @@
public static final int EVENT_INPUT_HIDDEN = 2;
/**
+ * The auto-fill input UI affordance associated with the view won't be shown because
+ * autofill is not available.
+ *
+ * <p>If the view provides its own auto-complete UI affordance but was not displaying it
+ * to avoid flickering, it could shown it upon receiving this event.
+ */
+ public static final int EVENT_INPUT_UNAVAILABLE = 3;
+
+ /**
* Called after a change in the autofill state associated with a view.
*
* @param view view associated with the change.
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 85b05e5..97210cc 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -32,7 +32,7 @@
boolean addClient(in IAutoFillManagerClient client, int userId);
oneway void startSession(in IBinder activityToken, IBinder windowToken, in IBinder appCallback,
in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
- boolean hasCallback, int flags);
+ boolean hasCallback, int flags, String packageName);
oneway void updateSession(in IBinder activityToken, in AutofillId id, in Rect bounds,
in AutofillValue value, int flags, int userId);
oneway void finishSession(in IBinder activityToken, int userId);
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index 020e80a..fae5742 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -514,14 +514,15 @@
}
@Override
- public void autofill(AutofillValue value) {
- if (!isEnabled()) return;
+ public boolean autofill(AutofillValue value) {
+ if (!isEnabled()) return false;
if (value.isList()) {
setSelection(value.getListValue());
} else {
Log.w(LOG_TAG, value + " could not be autofilled into " + this);
}
+ return true;
}
@Override
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 899a824..9dc61ab 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -584,14 +584,16 @@
}
@Override
- public void autofill(AutofillValue value) {
- if (!isEnabled()) return;
+ public boolean autofill(AutofillValue value) {
+ if (!isEnabled()) return false;
if (value.isToggle()) {
setChecked(value.getToggleValue());
} else {
Log.w(LOG_TAG, value + " could not be autofilled into " + this);
}
+
+ return true;
}
@Override
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index f63573f..7d04f35 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -775,14 +775,16 @@
}
@Override
- public void autofill(AutofillValue value) {
- if (!isEnabled()) return;
+ public boolean autofill(AutofillValue value) {
+ if (!isEnabled()) return false;
if (value.isDate()) {
mDelegate.updateDate(value.getDateValue());
} else {
Log.w(LOG_TAG, value + " could not be autofilled into " + this);
}
+
+ return true;
}
@Override
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 5e8279a..a7574c7 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -426,23 +426,24 @@
}
@Override
- public void autofill(AutofillValue value) {
- if (!isEnabled()) return;
+ public boolean autofill(AutofillValue value) {
+ if (!isEnabled()) return false;
int index;
if (value.isList()) {
index = value.getListValue();
} else {
Log.w(LOG_TAG, value + " could not be autofilled into " + this);
- return;
+ return false;
}
final View child = getChildAt(index);
if (child == null) {
Log.w(VIEW_LOG_TAG, "RadioGroup.autoFill(): no child with index " + index);
- return;
+ return false;
}
check(child.getId());
+ return true;
}
@Override
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index c5c317d..26edc43 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10028,14 +10028,17 @@
}
@Override
- public void autofill(AutofillValue value) {
+ public boolean autofill(AutofillValue value) {
if (value.isText()) {
if (isTextEditable()) {
setText(value.getTextValue(), mBufferType, true, 0);
+ return true;
}
} else {
Log.w(LOG_TAG, value + " could not be autofilled into " + this);
}
+
+ return false;
}
@Override
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index cfa78b5..1e97e3b 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -530,14 +530,16 @@
}
@Override
- public void autofill(AutofillValue value) {
- if (!isEnabled()) return;
+ public boolean autofill(AutofillValue value) {
+ if (!isEnabled()) return false;
if (value.isDate()) {
mDelegate.setDate(value.getDateValue());
} else {
Log.w(LOG_TAG, value + " could not be autofilled into " + this);
}
+
+ return true;
}
@Override
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index 80207ee..e86932c 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -115,6 +115,7 @@
// Lets calculate how many lines the given measurement allows us.
int availableHeight = height - mPaddingTop - mPaddingBottom;
int maxLines = availableHeight / getLineHeight();
+ maxLines = Math.max(1, maxLines);
if (getMaxLines() > 0) {
maxLines = Math.min(getMaxLines(), maxLines);
}
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index b259ad1..1104318 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -16,8 +16,6 @@
package com.android.internal.widget;
-import com.android.internal.R;
-
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.TypedArray;
@@ -28,6 +26,8 @@
import android.view.ViewGroup;
import android.widget.RemoteViews;
+import com.android.internal.R;
+
/**
* A custom-built layout for the Notification.MessagingStyle.
*
@@ -119,23 +119,30 @@
}
final View child = getChildAt(i);
LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
-
+ ImageFloatingTextView textChild = null;
if (child instanceof ImageFloatingTextView) {
// Pretend we need the image padding for all views, we don't know which
// one will end up needing to do this (might end up not using all the space,
// but calculating this exactly would be more expensive).
- ((ImageFloatingTextView) child).setNumIndentLines(
- mIndentLines == 2 ? 3 : mIndentLines);
+ textChild = (ImageFloatingTextView) child;
+ textChild.setNumIndentLines(mIndentLines == 2 ? 3 : mIndentLines);
}
- measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+ int spacing = first ? 0 : mSpacing;
+ measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, totalHeight
+ - mPaddingTop - mPaddingBottom + spacing);
final int childHeight = child.getMeasuredHeight();
int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
- lp.bottomMargin + (first ? 0 : mSpacing));
+ lp.bottomMargin + spacing);
first = false;
+ boolean measuredTooSmall = false;
+ if (textChild != null) {
+ measuredTooSmall = childHeight < textChild.getLayout().getHeight()
+ + textChild.getPaddingTop() + textChild.getPaddingBottom();
+ }
- if (newHeight <= targetHeight) {
+ if (newHeight <= targetHeight && !measuredTooSmall) {
totalHeight = newHeight;
lp.hide = false;
} else {
@@ -168,7 +175,15 @@
}
boolean changed = textChild.setNumIndentLines(Math.max(0, imageLines));
if (changed || !recalculateVisibility) {
- measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+ final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
+ mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
+ lp.width);
+ // we want to measure it at most as high as it is currently, otherwise we'll
+ // drop later lines
+ final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+ targetHeight - child.getMeasuredHeight(), lp.height);
+
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);;
}
imageLines -= textChild.getLineCount();
}
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index 79439e2..5553a3e 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -30,7 +30,7 @@
class SkColorFilterGlue {
public:
- static void finalizer(JNIEnv* env, jobject clazz, jlong skFilterHandle) {
+ static void SafeUnref(JNIEnv* env, jobject clazz, jlong skFilterHandle) {
SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
SkSafeUnref(filter);
}
@@ -57,19 +57,19 @@
};
static const JNINativeMethod colorfilter_methods[] = {
- {"destroyFilter", "(J)V", (void*) SkColorFilterGlue::finalizer}
+ {"nSafeUnref", "(J)V", (void*) SkColorFilterGlue::SafeUnref}
};
static const JNINativeMethod porterduff_methods[] = {
- { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter },
+ { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter },
};
static const JNINativeMethod lighting_methods[] = {
- { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter },
+ { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter },
};
static const JNINativeMethod colormatrix_methods[] = {
- { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter },
+ { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter },
};
int register_android_graphics_ColorFilter(JNIEnv* env) {
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 1bd2333..678041f 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -404,6 +404,11 @@
signalExceptionForError(env, err);
}
+static void JHwParcel_native_release(
+ JNIEnv *env, jobject thiz) {
+ JHwParcel::GetNativeContext(env, thiz)->setParcel(NULL, false /* assumeOwnership */);
+}
+
static void JHwParcel_native_releaseTemporaryStorage(
JNIEnv *env, jobject thiz) {
JHwParcel::GetNativeContext(env, thiz)->getStorage()->release(env);
@@ -955,6 +960,10 @@
{ "writeBuffer", "(L" PACKAGE_PATH "/HwBlob;)V",
(void *)JHwParcel_native_writeBuffer },
+
+ { "release", "()V",
+ (void *)JHwParcel_native_release },
+
};
namespace android {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c991f22..58e4051 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3593,7 +3593,7 @@
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
- <service android:name="com.android.server.BackgroundDexOptJobService"
+ <service android:name="com.android.server.pm.BackgroundDexOptService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6e0d9dc..385f256 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1386,6 +1386,9 @@
<!-- Boolean indicating if current platform supports BLE peripheral mode -->
<bool name="config_bluetooth_le_peripheral_mode_supported">false</bool>
+ <!-- Boolean indicating if current platform supports HFP inband ringing -->
+ <bool name="config_bluetooth_hfp_inband_ringing_support">false</bool>
+
<!-- Max number of scan filters supported by blutooth controller. 0 if the
device does not support hardware scan filters-->
<integer translatable="false" name="config_bluetooth_max_scan_filters">0</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ab978e1..0d4a407 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -242,6 +242,7 @@
<java-symbol type="bool" name="config_bluetooth_address_validation" />
<java-symbol type="bool" name="config_bluetooth_sco_off_call" />
<java-symbol type="bool" name="config_bluetooth_le_peripheral_mode_supported" />
+ <java-symbol type="bool" name="config_bluetooth_hfp_inband_ringing_support" />
<java-symbol type="bool" name="config_cellBroadcastAppLinks" />
<java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
<java-symbol type="bool" name="config_enableAutoPowerModes" />
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index fba8e23..dbc9e5d 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -40,6 +40,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common org.apache.http.legacy
LOCAL_PACKAGE_NAME := FrameworksCoreTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java
index ac62bf4..0ca3729 100644
--- a/graphics/java/android/graphics/ColorFilter.java
+++ b/graphics/java/android/graphics/ColorFilter.java
@@ -28,21 +28,51 @@
*/
public class ColorFilter {
/**
- * Holds the pointer to the native SkColorFilter instance.
- *
- * @hide
+ * @deprecated Use subclass constructors directly instead.
*/
- public long native_instance;
+ @Deprecated
+ public ColorFilter() {}
+
+ /**
+ * Holds the pointer to the native SkColorFilter instance.
+ */
+ private long mNativeInstance;
+
+ long createNativeInstance() {
+ return 0;
+ }
+
+ void discardNativeInstance() {
+ if (mNativeInstance != 0) {
+ nSafeUnref(mNativeInstance);
+ mNativeInstance = 0;
+ }
+ }
@Override
protected void finalize() throws Throwable {
try {
- super.finalize();
+ if (mNativeInstance != 0) {
+ nSafeUnref(mNativeInstance);
+ }
+ mNativeInstance = -1;
} finally {
- destroyFilter(native_instance);
- native_instance = 0;
+ super.finalize();
}
}
- static native void destroyFilter(long native_instance);
+ /** @hide */
+ public long getNativeInstance() {
+ if (mNativeInstance == -1) {
+ throw new IllegalStateException("attempting to use a finalized ColorFilter");
+ }
+
+ if (mNativeInstance == 0) {
+ mNativeInstance = createNativeInstance();
+ }
+ return mNativeInstance;
+
+ }
+
+ static native void nSafeUnref(long native_instance);
}
diff --git a/graphics/java/android/graphics/ColorMatrix.java b/graphics/java/android/graphics/ColorMatrix.java
index 1b1849e..6299b2c 100644
--- a/graphics/java/android/graphics/ColorMatrix.java
+++ b/graphics/java/android/graphics/ColorMatrix.java
@@ -268,4 +268,21 @@
m[5] = 1; m[6] = -0.34414f; m[7] = -0.71414f;
m[10] = 1; m[11] = 1.772f; m[12] = 0;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ // if (obj == this) return true; -- NaN value would mean matrix != itself
+ if (!(obj instanceof ColorMatrix)) {
+ return false;
+ }
+
+ // we don't use Arrays.equals(), since that considers NaN == NaN
+ final float[] other = ((ColorMatrix) obj).mArray;
+ for (int i = 0; i < 20; i++) {
+ if (other[i] != mArray[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java
index 291c8ff..61f6cc5 100644
--- a/graphics/java/android/graphics/ColorMatrixColorFilter.java
+++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java
@@ -16,6 +16,9 @@
package android.graphics;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
/**
* A color filter that transforms colors through a 4x5 color matrix. This filter
* can be used to change the saturation of pixels, convert from YUV to RGB, etc.
@@ -32,9 +35,8 @@
* the filter, so changes made to the matrix after the filter
* is constructed will not be reflected in the filter.
*/
- public ColorMatrixColorFilter(ColorMatrix matrix) {
+ public ColorMatrixColorFilter(@NonNull ColorMatrix matrix) {
mMatrix.set(matrix);
- update();
}
/**
@@ -44,84 +46,76 @@
* matrix. The first 20 entries of the array are copied into
* the filter. See ColorMatrix.
*/
- public ColorMatrixColorFilter(float[] array) {
+ public ColorMatrixColorFilter(@NonNull float[] array) {
if (array.length < 20) {
throw new ArrayIndexOutOfBoundsException();
}
mMatrix.set(array);
- update();
}
/**
- * Returns the {@link ColorMatrix} used by this filter. The returned
- * value is never null. Modifying the returned matrix does not have
- * any effect until you call {@link #setColorMatrix(ColorMatrix)}.
+ * Copies the ColorMatrix from the filter into the passed ColorMatrix.
*
- * @see #setColorMatrix(ColorMatrix)
- *
- * @hide
+ * @param colorMatrix Set to the current value of the filter's ColorMatrix.
*/
- public ColorMatrix getColorMatrix() {
- return mMatrix;
+ public void getColorMatrix(ColorMatrix colorMatrix) {
+ colorMatrix.set(mMatrix);
}
/**
- * Specifies the color matrix used by this filter. If the specified
- * color matrix is null, this filter's color matrix will be reset to
- * the identity matrix.
+ * Copies the provided color matrix to be used by this filter.
+ *
+ * If the specified color matrix is null, this filter's color matrix will be reset to the
+ * identity matrix.
*
* @param matrix A {@link ColorMatrix} or null
*
- * @see #getColorMatrix()
- * @see android.graphics.ColorMatrix#reset()
- * @see #setColorMatrix(float[])
- *
- * @hide
+ * @see #getColorMatrix(ColorMatrix)
+ * @see #setColorMatrixArray(float[])
+ * @see ColorMatrix#reset()
*/
- public void setColorMatrix(ColorMatrix matrix) {
+ public void setColorMatrix(@Nullable ColorMatrix matrix) {
+ discardNativeInstance();
if (matrix == null) {
mMatrix.reset();
- } else if (matrix != mMatrix) {
+ } else {
mMatrix.set(matrix);
}
- update();
}
/**
- * Specifies the color matrix used by this filter. If the specified
- * color matrix is null, this filter's color matrix will be reset to
- * the identity matrix.
+ * Copies the provided color matrix to be used by this filter.
+ *
+ * If the specified color matrix is null, this filter's color matrix will be reset to the
+ * identity matrix.
*
* @param array Array of floats used to transform colors, treated as a 4x5
* matrix. The first 20 entries of the array are copied into
* the filter. See {@link ColorMatrix}.
*
- * @see #getColorMatrix()
- * @see android.graphics.ColorMatrix#reset()
+ * @see #getColorMatrix(ColorMatrix)
* @see #setColorMatrix(ColorMatrix)
+ * @see ColorMatrix#reset()
*
* @throws ArrayIndexOutOfBoundsException if the specified array's
* length is < 20
- *
- * @hide
*/
- public void setColorMatrix(float[] array) {
+ public void setColorMatrixArray(@Nullable float[] array) {
+ // called '...Array' so that passing null isn't ambiguous
+ discardNativeInstance();
if (array == null) {
mMatrix.reset();
} else {
if (array.length < 20) {
throw new ArrayIndexOutOfBoundsException();
}
-
mMatrix.set(array);
}
- update();
}
- private void update() {
- final float[] colorMatrix = mMatrix.getArray();
- destroyFilter(native_instance);
- native_instance = nativeColorMatrixFilter(colorMatrix);
+ @Override
+ long createNativeInstance() {
+ return nativeColorMatrixFilter(mMatrix.getArray());
}
private static native long nativeColorMatrixFilter(float[] array);
diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java
index ad78430..b0c145b 100644
--- a/graphics/java/android/graphics/LightingColorFilter.java
+++ b/graphics/java/android/graphics/LightingColorFilter.java
@@ -21,6 +21,8 @@
package android.graphics;
+import android.annotation.ColorInt;
+
/**
* A color filter that can be used to simulate simple lighting effects.
* A <code>LightingColorFilter</code> is defined by two parameters, one
@@ -37,7 +39,9 @@
* The result is pinned to the <code>[0..255]</code> range for each channel.
*/
public class LightingColorFilter extends ColorFilter {
+ @ColorInt
private int mMul;
+ @ColorInt
private int mAdd;
/**
@@ -45,10 +49,9 @@
* and then adds a second color. The alpha components of the mul and add
* arguments are ignored.
*/
- public LightingColorFilter(int mul, int add) {
+ public LightingColorFilter(@ColorInt int mul, @ColorInt int add) {
mMul = mul;
mAdd = add;
- update();
}
/**
@@ -56,9 +59,8 @@
* color filter is applied.
*
* @see #setColorMultiply(int)
- *
- * @hide
*/
+ @ColorInt
public int getColorMultiply() {
return mMul;
}
@@ -69,12 +71,12 @@
* The alpha channel of this color is ignored.
*
* @see #getColorMultiply()
- *
- * @hide
*/
- public void setColorMultiply(int mul) {
- mMul = mul;
- update();
+ public void setColorMultiply(@ColorInt int mul) {
+ if (mMul != mul) {
+ mMul = mul;
+ discardNativeInstance();
+ }
}
/**
@@ -82,9 +84,8 @@
* when the color filter is applied.
*
* @see #setColorAdd(int)
- *
- * @hide
*/
+ @ColorInt
public int getColorAdd() {
return mAdd;
}
@@ -95,17 +96,17 @@
* The alpha channel of this color is ignored.
*
* @see #getColorAdd()
- *
- * @hide
*/
- public void setColorAdd(int add) {
- mAdd = add;
- update();
+ public void setColorAdd(@ColorInt int add) {
+ if (mAdd != add) {
+ mAdd = add;
+ discardNativeInstance();
+ }
}
- private void update() {
- destroyFilter(native_instance);
- native_instance = native_CreateLightingFilter(mMul, mAdd);
+ @Override
+ long createNativeInstance() {
+ return native_CreateLightingFilter(mMul, mAdd);
}
private static native long native_CreateLightingFilter(int mul, int add);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 7ca4615..5d6aa8a 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -42,7 +42,8 @@
public class Paint {
private long mNativePaint;
- private long mNativeShader = 0;
+ private long mNativeShader;
+ private long mNativeColorFilter;
// The approximate size of a native paint object.
private static final long NATIVE_PAINT_SIZE = 98;
@@ -584,6 +585,11 @@
mNativeShader = newNativeShader;
nSetShader(mNativePaint, mNativeShader);
}
+ long newNativeColorFilter = mColorFilter == null ? 0 : mColorFilter.getNativeInstance();
+ if (newNativeColorFilter != mNativeColorFilter) {
+ mNativeColorFilter = newNativeColorFilter;
+ nSetColorFilter(mNativePaint, mNativeColorFilter);
+ }
return mNativePaint;
}
@@ -1044,10 +1050,13 @@
* @return filter
*/
public ColorFilter setColorFilter(ColorFilter filter) {
- long filterNative = 0;
- if (filter != null)
- filterNative = filter.native_instance;
- nSetColorFilter(mNativePaint, filterNative);
+ // If mColorFilter changes, cached value of native shader aren't valid, since
+ // old shader's pointer may be reused by another shader allocation later
+ if (mColorFilter != filter) {
+ mNativeColorFilter = -1;
+ }
+
+ // Defer setting the filter natively until getNativeInstance() is called
mColorFilter = filter;
return filter;
}
diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java
index 69d6891..ccc6ead 100644
--- a/graphics/java/android/graphics/PorterDuffColorFilter.java
+++ b/graphics/java/android/graphics/PorterDuffColorFilter.java
@@ -24,6 +24,7 @@
* color and a specific {@link PorterDuff Porter-Duff composite mode}.
*/
public class PorterDuffColorFilter extends ColorFilter {
+ @ColorInt
private int mColor;
private PorterDuff.Mode mMode;
@@ -40,7 +41,6 @@
public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
mColor = color;
mMode = mode;
- update();
}
/**
@@ -49,9 +49,8 @@
*
* @see Color
* @see #setColor(int)
- *
- * @hide
*/
+ @ColorInt
public int getColor() {
return mColor;
}
@@ -65,12 +64,12 @@
* @see Color
* @see #getColor()
* @see #getMode()
- *
- * @hide
*/
- public void setColor(int color) {
- mColor = color;
- update();
+ public void setColor(@ColorInt int color) {
+ if (mColor != color) {
+ mColor = color;
+ discardNativeInstance();
+ }
}
/**
@@ -79,8 +78,6 @@
*
* @see PorterDuff
* @see #setMode(android.graphics.PorterDuff.Mode)
- *
- * @hide
*/
public PorterDuff.Mode getMode() {
return mMode;
@@ -93,17 +90,18 @@
* @see PorterDuff
* @see #getMode()
* @see #getColor()
- *
- * @hide
*/
public void setMode(@NonNull PorterDuff.Mode mode) {
+ if (mode == null) {
+ throw new IllegalArgumentException("mode must be non-null");
+ }
mMode = mode;
- update();
+ discardNativeInstance();
}
- private void update() {
- destroyFilter(native_instance);
- native_instance = native_CreatePorterDuffFilter(mColor, mMode.nativeInt);
+ @Override
+ long createNativeInstance() {
+ return native_CreatePorterDuffFilter(mColor, mMode.nativeInt);
}
@Override
@@ -115,10 +113,7 @@
return false;
}
final PorterDuffColorFilter other = (PorterDuffColorFilter) object;
- if (mColor != other.mColor || mMode != other.mMode) {
- return false;
- }
- return true;
+ return (mColor == other.mColor && mMode.nativeInt == other.mMode.nativeInt);
}
@Override
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index b584e0d..8410ab2 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -106,8 +106,10 @@
}
void discardNativeInstance() {
- nativeSafeUnref(mNativeInstance);
- mNativeInstance = 0;
+ if (mNativeInstance != 0) {
+ nativeSafeUnref(mNativeInstance);
+ mNativeInstance = 0;
+ }
}
/**
@@ -120,7 +122,9 @@
@Override
protected void finalize() throws Throwable {
try {
- nativeSafeUnref(mNativeInstance);
+ if (mNativeInstance != 0) {
+ nativeSafeUnref(mNativeInstance);
+ }
mNativeInstance = -1;
} finally {
super.finalize();
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index 0722c18..c6c9271 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -218,6 +218,8 @@
}
/**
+ * Only call this method after bound is set on this drawable.
+ *
* @return the mask path object used to clip the drawable
*/
public Path getIconMask() {
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 3a12419..a1539b8 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -333,7 +333,7 @@
// Color filters always override tint filters.
final ColorFilter colorFilter = (mColorFilter == null ? mTintFilter : mColorFilter);
final long colorFilterNativeInstance = colorFilter == null ? 0 :
- colorFilter.native_instance;
+ colorFilter.getNativeInstance();
boolean canReuseCache = mVectorState.canReuseCache();
int pixelCount = nDraw(mVectorState.getNativeRenderer(), canvas.getNativeCanvasWrapper(),
colorFilterNativeInstance, mTmpBounds, needMirroring(),
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
index d8afa35..a738ba4 100644
--- a/libs/hwui/FloatColor.h
+++ b/libs/hwui/FloatColor.h
@@ -38,13 +38,14 @@
}
// "color" is a gamma-encoded sRGB color
- // After calling this method, the color is stored as a linear color. The color
- // is not pre-multiplied.
- void setUnPreMultipliedSRGB(uint32_t color) {
+ // After calling this method, the color is stored as a un-premultiplied linear color
+ // if linear blending is enabled. Otherwise, the color is stored as a un-premultiplied
+ // gamma-encoded sRGB color
+ void setUnPreMultiplied(uint32_t color) {
a = ((color >> 24) & 0xff) / 255.0f;
- r = EOCF_sRGB(((color >> 16) & 0xff) / 255.0f);
- g = EOCF_sRGB(((color >> 8) & 0xff) / 255.0f);
- b = EOCF_sRGB(((color ) & 0xff) / 255.0f);
+ r = EOCF(((color >> 16) & 0xff) / 255.0f);
+ g = EOCF(((color >> 8) & 0xff) / 255.0f);
+ b = EOCF(((color ) & 0xff) / 255.0f);
}
bool isNotBlack() {
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 18bfcc2..dceb285 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -189,9 +189,9 @@
float amount, uint8_t*& dst) const {
float oppAmount = 1.0f - amount;
float a = start.a * oppAmount + end.a * amount;
- *dst++ = uint8_t(a * OECF_sRGB((start.r * oppAmount + end.r * amount)) * 255.0f);
- *dst++ = uint8_t(a * OECF_sRGB((start.g * oppAmount + end.g * amount)) * 255.0f);
- *dst++ = uint8_t(a * OECF_sRGB((start.b * oppAmount + end.b * amount)) * 255.0f);
+ *dst++ = uint8_t(a * OECF(start.r * oppAmount + end.r * amount) * 255.0f);
+ *dst++ = uint8_t(a * OECF(start.g * oppAmount + end.g * amount) * 255.0f);
+ *dst++ = uint8_t(a * OECF(start.b * oppAmount + end.b * amount) * 255.0f);
*dst++ = uint8_t(a * 255.0f);
}
@@ -201,17 +201,14 @@
float a = start.a * oppAmount + end.a * amount;
float* d = (float*) dst;
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
+ // We want to stay linear
*d++ = a * (start.r * oppAmount + end.r * amount);
*d++ = a * (start.g * oppAmount + end.g * amount);
*d++ = a * (start.b * oppAmount + end.b * amount);
#else
- // What we're doing to the alpha channel here is technically incorrect
- // but reproduces Android's old behavior when the alpha was pre-multiplied
- // with gamma-encoded colors
- a = EOCF_sRGB(a);
- *d++ = a * OECF_sRGB(start.r * oppAmount + end.r * amount);
- *d++ = a * OECF_sRGB(start.g * oppAmount + end.g * amount);
- *d++ = a * OECF_sRGB(start.b * oppAmount + end.b * amount);
+ *d++ = a * OECF(start.r * oppAmount + end.r * amount);
+ *d++ = a * OECF(start.g * oppAmount + end.g * amount);
+ *d++ = a * OECF(start.b * oppAmount + end.b * amount);
#endif
*d++ = a;
dst += 4 * sizeof(float);
@@ -232,10 +229,10 @@
ChannelMixer mix = gMixers[mUseFloatTexture];
FloatColor start;
- start.setUnPreMultipliedSRGB(colors[0]);
+ start.setUnPreMultiplied(colors[0]);
FloatColor end;
- end.setUnPreMultipliedSRGB(colors[1]);
+ end.setUnPreMultiplied(colors[1]);
int currentPos = 1;
float startPos = positions[0];
@@ -250,7 +247,7 @@
currentPos++;
- end.setUnPreMultipliedSRGB(colors[currentPos]);
+ end.setUnPreMultiplied(colors[currentPos]);
distance = positions[currentPos] - startPos;
}
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 40ab778..38c23e4 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -190,7 +190,7 @@
// Dithering must be done in the quantization space
// When we are writing to an sRGB framebuffer, we must do the following:
// EOTF(OETF(color) + dither)
-// The dithering pattern is generated with a triangle noise generator in the range [-0.0,1.0]
+// The dithering pattern is generated with a triangle noise generator in the range [-1.0,1.0]
// TODO: Handle linear fp16 render targets
const char* gFS_Gradient_Functions = R"__SHADER__(
float triangleNoise(const highp vec2 n) {
@@ -202,23 +202,26 @@
)__SHADER__";
const char* gFS_Gradient_Preamble[2] = {
// Linear framebuffer
- "\nvec4 dither(const vec4 color) {\n"
- " return vec4(color.rgb + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0), color.a);\n"
- "}\n"
- "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n"
- " vec4 c = mix(a, b, v);\n"
- " c.a = EOTF_sRGB(c.a);\n" // This is technically incorrect but preserves compatibility
- " return vec4(OETF_sRGB(c.rgb) * c.a, c.a);\n"
- "}\n",
+ R"__SHADER__(
+ vec4 dither(const vec4 color) {
+ return color + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
+ }
+ vec4 gradientMix(const vec4 a, const vec4 b, float v) {
+ vec4 c = mix(a, b, v);
+ return vec4(c.rgb * c.a, c.a);
+ }
+ )__SHADER__",
// sRGB framebuffer
- "\nvec4 dither(const vec4 color) {\n"
- " vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);\n"
- " return vec4(dithered * dithered, color.a);\n"
- "}\n"
- "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n"
- " vec4 c = mix(a, b, v);\n"
- " return vec4(c.rgb * c.a, c.a);\n"
- "}\n"
+ R"__SHADER__(
+ vec4 dither(const vec4 color) {
+ vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
+ return vec4(dithered * dithered, color.a);
+ }
+ vec4 gradientMixMix(const vec4 a, const vec4 b, float v) {
+ vec4 c = mix(a, b, v);
+ return vec4(c.rgb * c.a, c.a);
+ }
+ )__SHADER__",
};
// Uses luminance coefficients from Rec.709 to choose the appropriate gamma
@@ -272,19 +275,19 @@
// Linear
" vec4 gradientColor = texture2D(gradientSampler, linear);\n",
- " vec4 gradientColor = gammaMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
+ " vec4 gradientColor = gradientMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
// Circular
" vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
- " vec4 gradientColor = gammaMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
+ " vec4 gradientColor = gradientMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
// Sweep
" highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
" vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
" highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
- " vec4 gradientColor = gammaMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
+ " vec4 gradientColor = gradientMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
};
const char* gFS_Main_FetchBitmap =
" vec4 bitmapColor = OETF(texture2D(bitmapSampler, outBitmapTexCoords));\n";
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 760c10c..4f7f9d7 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -173,8 +173,8 @@
outData->gradientSampler = 0;
outData->gradientTexture = nullptr;
- outData->startColor.setUnPreMultipliedSRGB(gradInfo.fColors[0]);
- outData->endColor.setUnPreMultipliedSRGB(gradInfo.fColors[1]);
+ outData->startColor.setUnPreMultiplied(gradInfo.fColors[0]);
+ outData->endColor.setUnPreMultiplied(gradInfo.fColors[1]);
}
return true;
diff --git a/libs/hwui/VkLayer.cpp b/libs/hwui/VkLayer.cpp
index 537b3ea..ef4784b 100644
--- a/libs/hwui/VkLayer.cpp
+++ b/libs/hwui/VkLayer.cpp
@@ -29,7 +29,7 @@
SkImageInfo info = SkImageInfo::MakeS32(mWidth, mHeight, kPremul_SkAlphaType);
surface = SkSurface::MakeRenderTarget(mRenderState.getGrContext(), SkBudgeted::kNo, info);
surface->getCanvas()->clear(SK_ColorBLUE);
- mImage = surface->makeImageSnapshot(SkBudgeted::kNo);
+ mImage = surface->makeImageSnapshot();
}
void VkLayer::onVkContextDestroyed() {
diff --git a/packages/MtpDocumentsProvider/tests/Android.mk b/packages/MtpDocumentsProvider/tests/Android.mk
index e50d6fb..148cd0d 100644
--- a/packages/MtpDocumentsProvider/tests/Android.mk
+++ b/packages/MtpDocumentsProvider/tests/Android.mk
@@ -8,5 +8,6 @@
LOCAL_PACKAGE_NAME := MtpDocumentsProviderTests
LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider
LOCAL_CERTIFICATE := media
+LOCAL_COMPATIBILITY_SUITE := device-tests
include $(BUILD_PACKAGE)
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk
index d1d0ee4..3c02453 100644
--- a/packages/PrintSpooler/tests/outofprocess/Android.mk
+++ b/packages/PrintSpooler/tests/outofprocess/Android.mk
@@ -24,5 +24,6 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4
LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/tests/integ/Android.mk b/packages/SettingsLib/tests/integ/Android.mk
index 60d1c77..7ace048 100644
--- a/packages/SettingsLib/tests/integ/Android.mk
+++ b/packages/SettingsLib/tests/integ/Android.mk
@@ -25,6 +25,7 @@
LOCAL_JACK_FLAGS := --multi-dex native
LOCAL_PACKAGE_NAME := SettingsLibTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
diff --git a/packages/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk
index acd552d..48b757c 100644
--- a/packages/Shell/tests/Android.mk
+++ b/packages/Shell/tests/Android.mk
@@ -16,6 +16,7 @@
legacy-android-test \
LOCAL_PACKAGE_NAME := ShellTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_INSTRUMENTATION_FOR := Shell
LOCAL_CERTIFICATE := platform
diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
index 2b75c36..696e9b1 100644
--- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
+++ b/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
@@ -17,6 +17,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:color="@color/qs_tile_disabled_color" />
+ <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" />
<item android:color="@android:color/transparent" />
-</selector>
\ No newline at end of file
+</selector>
diff --git a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
index f296076..6415ecb4 100644
--- a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
+++ b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml
@@ -17,14 +17,15 @@
android:width="48.0dp"
android:height="48.0dp"
android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
<group
android:scaleX="1.2"
android:scaleY="1.2"
android:pivotX="12.0"
android:pivotY="12.0">
<path
- android:fillColor="@color/qs_user_detail_icon_muted"
+ android:fillColor="#FFFFFFFF"
android:pathData="M12.000000,2.000000C6.500000,2.000000 2.000000,6.500000 2.000000,12.000000s4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000S17.500000,2.000000 12.000000,2.000000zM17.000000,13.000000l-4.000000,0.000000l0.000000,4.000000l-2.000000,0.000000l0.000000,-4.000000L7.000000,13.000000l0.000000,-2.000000l4.000000,0.000000L11.000000,7.000000l2.000000,0.000000l0.000000,4.000000l4.000000,0.000000L17.000000,13.000000z"/>
</group>
</vector>
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index 8d1f9e4..e714cd6 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -14,24 +14,38 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:paddingTop="8dp">
+ <LinearLayout
+ android:id="@+id/label_group"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center_horizontal"
- android:paddingTop="8dp"
- android:paddingBottom="8dp">
- <TextView android:id="@+id/tile_label"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/tile_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textColor="?android:attr/textColorPrimary"
- android:gravity="center_horizontal"
- android:minLines="2"
+ android:clickable="false"
+ android:maxLines="2"
android:padding="0dp"
android:textAppearance="@style/TextAppearance.QS.TileLabel"
- android:clickable="false" />
- <ImageView android:id="@+id/restricted_padlock"
+ android:textColor="?android:attr/textColorPrimary"/>
+
+ <ImageView
+ android:id="@+id/expand_indicator"
+ android:layout_marginStart="4dp"
+ android:layout_width="12dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/qs_dual_tile_caret"
+ android:tint="?android:attr/textColorPrimary" />
+
+ <ImageView android:id="@+id/restricted_padlock"
android:layout_width="@dimen/qs_tile_text_size"
android:layout_height="match_parent"
android:paddingBottom="@dimen/qs_tile_text_size"
@@ -39,4 +53,17 @@
android:layout_marginLeft="@dimen/restricted_padlock_pading"
android:scaleType="centerInside"
android:visibility="gone" />
-</LinearLayout>
+ </LinearLayout>
+
+ <View
+ android:id="@+id/underline"
+ android:layout_width="30dp"
+ android:layout_height="1dp"
+ android:layout_marginTop="2dp"
+ android:layout_alignStart="@id/label_group"
+ android:layout_alignEnd="@id/label_group"
+ android:layout_below="@id/label_group"
+ android:alpha="?android:attr/disabledAlpha"
+ android:background="?android:attr/colorForeground"/>
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index 8c6c7cf..c7bfaef 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -53,7 +53,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/qs_detail_item_secondary_text_size"
- android:textColor="@color/qs_user_detail_name"
+ android:textColor="?android:attr/textColorSecondary"
android:gravity="center_horizontal" />
<ImageView
android:id="@+id/restricted_padlock"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index cbe822f..a549c73 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1160,7 +1160,8 @@
if (mOccluded != isOccluded) {
mOccluded = isOccluded;
- mStatusBarKeyguardViewManager.setOccluded(isOccluded, animate);
+ mStatusBarKeyguardViewManager.setOccluded(isOccluded, animate
+ && mDeviceInteractive);
adjustStatusBarLocked();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 2f9c3fc..0547cbb 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -249,6 +249,7 @@
private void showMenu(Rect stackBounds, Rect movementBounds) {
if (!mMenuVisible) {
+ setVisible(true);
updateActionViews(stackBounds);
if (mMenuContainerAnimator != null) {
mMenuContainerAnimator.cancel();
@@ -268,7 +269,10 @@
mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
mMenuContainerAnimator.start();
} else {
+ // If we are already visible, then just start the delayed dismiss and unregister any
+ // existing input consumers from the previous drag
repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
+ notifyUnregisterInputConsumer();
}
}
@@ -292,9 +296,7 @@
if (animationFinishedRunnable != null) {
animationFinishedRunnable.run();
}
- if (getSystemService(AccessibilityManager.class).isEnabled()) {
- finish();
- }
+ setVisible(false);
}
});
mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
@@ -398,6 +400,7 @@
}
private void updateDismissFraction(float fraction) {
+ setVisible(true);
int alpha;
if (mMenuVisible) {
mMenuContainer.setAlpha(1-fraction);
@@ -416,6 +419,12 @@
sendMessage(m, "Could not notify controller to register input consumer");
}
+ private void notifyUnregisterInputConsumer() {
+ Message m = Message.obtain();
+ m.what = PipMenuActivityController.MESSAGE_UNREGISTER_INPUT_CONSUMER;
+ sendMessage(m, "Could not notify controller to unregister input consumer");
+ }
+
private void notifyMenuVisibility(boolean visible) {
mMenuVisible = visible;
Message m = Message.obtain();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 7dc455b..724f453 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -63,6 +63,7 @@
public static final int MESSAGE_DISMISS_PIP = 103;
public static final int MESSAGE_UPDATE_ACTIVITY_CALLBACK = 104;
public static final int MESSAGE_REGISTER_INPUT_CONSUMER = 105;
+ public static final int MESSAGE_UNREGISTER_INPUT_CONSUMER = 106;
/**
* A listener interface to receive notification on changes in PIP.
@@ -135,6 +136,10 @@
mInputConsumerController.registerInputConsumer();
break;
}
+ case MESSAGE_UNREGISTER_INPUT_CONSUMER: {
+ mInputConsumerController.unregisterInputConsumer();
+ break;
+ }
case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
mToActivityMessenger = msg.replyTo;
mStartActivityRequested = false;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index c52fc3e..f70d5b4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -504,8 +504,8 @@
return false;
}
- try {
- if (ENABLE_DISMISS_DRAG_TO_TARGET) {
+ if (ENABLE_DISMISS_DRAG_TO_TARGET) {
+ try {
mHandler.removeCallbacks(mShowDismissAffordance);
PointF vel = mTouchState.getVelocity();
final float velocity = PointF.length(vel.x, vel.y);
@@ -520,9 +520,9 @@
return true;
}
}
+ } finally {
+ mDismissViewController.destroyDismissTarget();
}
- } finally {
- mDismissViewController.destroyDismissTarget();
}
if (touchState.isDragging()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index c0fb4d5..198cb9e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -41,10 +41,10 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.qs.QSDetailClipper;
import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
+import com.android.systemui.qs.QSDetailClipper;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.KeyguardMonitor.Callback;
@@ -74,6 +74,7 @@
private boolean mFinishedFetchingTiles = false;
private int mX;
private int mY;
+ private boolean mOpening;
public QSCustomizer(Context context, AttributeSet attrs) {
super(new ContextThemeWrapper(context, R.style.edit_theme), attrs);
@@ -140,6 +141,7 @@
mY = y;
MetricsLogger.visible(getContext(), MetricsProto.MetricsEvent.QS_EDIT);
isShown = true;
+ mOpening = true;
setTileSpecs();
setVisibility(View.VISIBLE);
mClipper.animateCircularClip(x, y, true, mExpandAnimationListener);
@@ -226,7 +228,7 @@
}
private final Callback mKeyguardCallback = () -> {
- if (Dependency.get(KeyguardMonitor.class).isShowing()) {
+ if (Dependency.get(KeyguardMonitor.class).isShowing() && !mOpening) {
hide(0, 0);
}
};
@@ -237,11 +239,13 @@
if (isShown) {
setCustomizing(true);
}
+ mOpening = false;
mNotifQsContainer.setCustomizerAnimating(false);
}
@Override
public void onAnimationCancel(Animator animation) {
+ mOpening = false;
mNotifQsContainer.setCustomizerAnimating(false);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 5ac7891..948954c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -369,7 +369,6 @@
Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
intent, 0);
} else {
- mAnnounceNextStateChange = true;
handleClick();
}
} else if (msg.what == SECONDARY_CLICK) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index 2c04e82..d2ae6e9f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -36,11 +36,12 @@
/** View that represents a standard quick settings tile. **/
public class QSTileView extends QSTileBaseView {
- private final View mDivider;
+ private View mDivider;
protected TextView mLabel;
private ImageView mPadLock;
private int mState;
private ViewGroup mLabelContainer;
+ private View mExpandIndicator;
public QSTileView(Context context, QSIconView icon) {
this(context, icon, false);
@@ -54,8 +55,6 @@
setClickable(true);
setId(View.generateViewId());
- mDivider = LayoutInflater.from(context).inflate(R.layout.divider, this, false);
- addView(mDivider);
createLabel();
setOrientation(VERTICAL);
setGravity(Gravity.CENTER);
@@ -81,8 +80,10 @@
.inflate(R.layout.qs_tile_label, this, false);
mLabelContainer.setClipChildren(false);
mLabelContainer.setClipToPadding(false);
- mLabel = (TextView) mLabelContainer.findViewById(R.id.tile_label);
- mPadLock = (ImageView) mLabelContainer.findViewById(R.id.restricted_padlock);
+ mLabel = mLabelContainer.findViewById(R.id.tile_label);
+ mPadLock = mLabelContainer.findViewById(R.id.restricted_padlock);
+ mDivider = mLabelContainer.findViewById(R.id.underline);
+ mExpandIndicator = mLabelContainer.findViewById(R.id.expand_indicator);
addView(mLabelContainer);
}
@@ -101,6 +102,7 @@
mLabel.setText(state.label);
}
mDivider.setVisibility(state.dualTarget ? View.VISIBLE : View.INVISIBLE);
+ mExpandIndicator.setVisibility(state.dualTarget ? View.VISIBLE : View.GONE);
if (state.dualTarget != mLabelContainer.isClickable()) {
mLabelContainer.setClickable(state.dualTarget);
mLabelContainer.setLongClickable(state.dualTarget);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 47468ae..ac24e2e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -67,6 +67,7 @@
import android.os.UserManager;
import android.provider.Settings;
import android.util.ArraySet;
+import android.util.LauncherIcons;
import android.util.Log;
import android.util.MutableBoolean;
import android.view.Display;
@@ -142,6 +143,7 @@
int mDummyThumbnailHeight;
Paint mBgProtectionPaint;
Canvas mBgProtectionCanvas;
+ LauncherIcons mLauncherIcons;
private final Handler mHandler = new H();
@@ -299,6 +301,7 @@
Collections.addAll(sRecentsBlacklist,
res.getStringArray(R.array.recents_blacklist_array));
}
+ mLauncherIcons = new LauncherIcons(context);
}
/**
@@ -834,7 +837,7 @@
return new ColorDrawable(0xFF666666);
}
- Drawable icon = info.loadIcon(mPm);
+ Drawable icon = mLauncherIcons.wrapIconDrawableWithShadow(info.loadIcon(mPm));
return getBadgedIcon(icon, userId);
}
@@ -850,7 +853,7 @@
return new ColorDrawable(0xFF666666);
}
- Drawable icon = appInfo.loadIcon(mPm);
+ Drawable icon = mLauncherIcons.wrapIconDrawableWithShadow(appInfo.loadIcon(mPm));
return getBadgedIcon(icon, userId);
}
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 576299f..10ff8ad 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -26,6 +26,7 @@
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
LOCAL_PACKAGE_NAME := SystemUITests
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-Iaidl-files-under, src) \
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 0cc2311..8a3b9af 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -56,6 +56,12 @@
// Type for APP_TRANSITION event: The transition brought an already existing activity to the
// front.
TYPE_TRANSITION_HOT_LAUNCH = 9;
+
+ // The action was successful
+ TYPE_SUCCESS = 10;
+
+ // The action failed
+ TYPE_FAILURE = 11;
}
// Known visual elements: views or controls.
@@ -3608,6 +3614,169 @@
// CATEGORY: SETTINGS
SETTINGS_LOCK_SCREEN_PREFERENCES = 882;
+ // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_APPOP_REQUEST_ACCESS_NOTIFICATIONS = 883;
+
+ // ACTION: An app was granted the app-op permission ACCESS_NOTIFICATIONS
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_APPOP_GRANT_ACCESS_NOTIFICATIONS = 884;
+
+ // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_APPOP_DENIED_ACCESS_NOTIFICATIONS = 885;
+
+ // ACTION: The app-op permission ACCESS_NOTIFICATIONS was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_APPOP_REVOKE_ACCESS_NOTIFICATIONS = 886;
+
+ // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_APPOP_REQUEST_SYSTEM_ALERT_WINDOW = 887;
+
+ // ACTION: An app was granted the app-op permission SYSTEM_ALERT_WINDOW
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_APPOP_GRANT_SYSTEM_ALERT_WINDOW = 888;
+
+ // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_APPOP_DENIED_SYSTEM_ALERT_WINDOW = 889;
+
+ // ACTION: The app-op permission SYSTEM_ALERT_WINDOW was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_APPOP_REVOKE_SYSTEM_ALERT_WINDOW = 890;
+
+ // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_APPOP_REQUEST_WRITE_SETTINGS = 891;
+
+ // ACTION: An app was granted the app-op permission REQUEST_WRITE_SETTINGS
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_APPOP_GRANT_WRITE_SETTINGS = 892;
+
+ // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_APPOP_DENIED_WRITE_SETTINGS = 893;
+
+ // ACTION: The app-op permission REQUEST_WRITE_SETTINGS was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_APPOP_REVOKE_WRITE_SETTINGS = 894;
+
+ // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_APPOP_REQUEST_REQUEST_INSTALL_PACKAGES = 895;
+
+ // ACTION: An app was granted the app-op permission REQUEST_INSTALL_PACKAGES
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_APPOP_GRANT_REQUEST_INSTALL_PACKAGES = 896;
+
+ // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_APPOP_DENIED_REQUEST_INSTALL_PACKAGES = 897;
+
+ // ACTION: The app-op permission REQUEST_INSTALL_PACKAGES was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_APPOP_REVOKE_REQUEST_INSTALL_PACKAGES = 898;
+
+ // ACTION: Phase 1 of instant application resolution occurred
+ // OS: O
+ ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE = 899;
+
+ // ACTION: Phase 2 of instant application resolution occurred
+ // OS: O
+ ACTION_INSTANT_APP_RESOLUTION_PHASE_TWO = 900;
+
+ // FIELD: The amount of time for an ephemeral resolution phase; in milliseconds
+ // OS: O
+ FIELD_INSTANT_APP_RESOLUTION_DELAY_MS = 901;
+
+ // FIELD: The status of an ephemeral resolution phase
+ // Value 0: success
+ // Value 1: no full hash match
+ // OS: O
+ FIELD_INSTANT_APP_RESOLUTION_STATUS = 902;
+
+ // FIELD - A token to identify all events that are part of the same instant application launch
+ // OS: O
+ FIELD_INSTANT_APP_LAUNCH_TOKEN = 903;
+
+ // FIELD - The name of the package responsible for launching the activity
+ // OS: O
+ APP_TRANSITION_CALLING_PACKAGE_NAME = 904;
+
+ // FIELD - Whether or not the launched activity is part of an instant application
+ // OS: O
+ APP_TRANSITION_IS_EPHEMERAL = 905;
+
+ // An autofill session was started
+ // Package: Package of app that is autofilled
+ AUTOFILL_SESSION_STARTED = 906;
+
+ // An autofill request was processed by a service
+ // Type TYPE_SUCCESS: The request succeeded
+ // Type TYPE_FAILURE: The request failed
+ // Package: Package of app that is autofilled
+ // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ // Tag FIELD_AUTOFILL_NUM_DATASET: The number of datasets returned (only in success case)
+ AUTOFILL_REQUEST = 907;
+
+ // Tag of a field for a package of an autofill service
+ FIELD_AUTOFILL_SERVICE = 908;
+
+ // Tag of a field for the number of datasets
+ FIELD_AUTOFILL_NUM_DATASETS = 909;
+
+ // An autofill dataset selection UI was shown
+ // Type TYPE_DISMISS: UI was explicityly canceled by the user
+ // Type TYPE_CLOSE: UI was destroyed without influence of the user
+ // Type TYPE_ACTION: dataset was selected
+ // Type TYPE_DETAIL: authentication was selected
+ // 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
+ AUTOFILL_FILL_UI = 910;
+
+ // Tag of a field for the length of the filter text
+ FIELD_AUTOFILL_FILTERTEXT_LEN = 911;
+
+ // An autofill authentification succeeded
+ // Package: Package of app that was autofilled
+ AUTOFILL_AUTHENTICATED = 912;
+
+ // An activity was autofilled and all values could be applied
+ // Package: Package of app that is autofilled
+ // Tag FIELD_AUTOFILL_NUM_VALUES: Number of values that were suggested to be autofilled
+ // Tag FIELD_AUTOFILL_NUM_VIEWS_FILLED: Number of views that could be filled
+ AUTOFILL_DATASET_APPLIED = 913;
+
+ // Tag of a field for the number values to be filled in
+ FIELD_AUTOFILL_NUM_VALUES = 914;
+
+ // Tag of a field for the number of views that were filled
+ FIELD_AUTOFILL_NUM_VIEWS_FILLED = 915;
+
+ // An autofill save UI was shown
+ // Type TYPE_DISMISS: UI was explicityly canceled by the user
+ // 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
+ AUTOFILL_SAVE_UI = 916;
+
+ // Tag of a field for the number of saveable ids
+ FIELD_AUTOFILL_NUM_IDS = 917;
+
+ // ACTION: An autofill service was reqiested to save data
+ // Type TYPE_SUCCESS: The request succeeded
+ // Type TYPE_FAILURE: The request failed
+ // Package: Package of app that was autofilled
+ // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+ AUTOFILL_DATA_SAVE_REQUEST = 918;
+
+ // An auto-fill session was finished
+ // Package: Package of app that was autofilled
+ AUTOFILL_SESSION_FINISHED = 919;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index af1193d..c7ba1ff 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -28,6 +28,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.graphics.Rect;
@@ -53,6 +54,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -316,13 +318,27 @@
@Override
public void startSession(IBinder activityToken, IBinder windowToken, IBinder appCallback,
AutofillId autofillId, Rect bounds, AutofillValue value, int userId,
- boolean hasCallback, int flags) {
+ boolean hasCallback, int flags, String packageName) {
// TODO(b/33197203): make sure it's called by resumed / focused activity
+ activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
+ appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
+ autofillId = Preconditions.checkNotNull(autofillId, "autoFillId");
+ bounds = Preconditions.checkNotNull(bounds, "bounds");
+ packageName = Preconditions.checkNotNull(packageName, "packageName");
+
+ Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId");
+
+ try {
+ mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException(packageName + " is not a valid package", e);
+ }
+
synchronized (mLock) {
final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
service.startSessionLocked(activityToken, windowToken, appCallback,
- autofillId, bounds, value, hasCallback, flags);
+ autofillId, bounds, value, hasCallback, flags, packageName);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 3e5ad82..cde3946 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -28,6 +28,7 @@
import static com.android.server.autofill.Helper.VERBOSE;
import static com.android.server.autofill.Helper.findValue;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
@@ -43,6 +44,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.graphics.Rect;
+import android.metrics.LogMaker;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -67,7 +69,11 @@
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
+import android.view.autofill.AutofillManager.AutofillCallback;
+
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.IResultReceiver;
import com.android.server.autofill.ui.AutoFillUI;
@@ -92,6 +98,7 @@
private final Context mContext;
private final Object mLock;
private final AutoFillUI mUi;
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
private RemoteCallbackList<IAutoFillManagerClient> mClients;
private AutofillServiceInfo mInfo;
@@ -284,9 +291,10 @@
}
}
- void startSessionLocked(IBinder activityToken, IBinder windowToken, IBinder appCallbackToken,
- AutofillId autofillId, Rect bounds, AutofillValue value, boolean hasCallback,
- int flags) {
+ void startSessionLocked(@NonNull IBinder activityToken, @Nullable IBinder windowToken,
+ @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, @NonNull Rect bounds,
+ @Nullable AutofillValue value, boolean hasCallback, int flags,
+ @NonNull String packageName) {
if (!hasService()) {
return;
}
@@ -305,7 +313,7 @@
}
final Session newSession = createSessionByTokenLocked(activityToken,
- windowToken, appCallbackToken, hasCallback, flags);
+ windowToken, appCallbackToken, hasCallback, flags, packageName);
newSession.updateLocked(autofillId, bounds, value, FLAG_START_SESSION);
}
@@ -337,10 +345,11 @@
session.destroyLocked();
}
- private Session createSessionByTokenLocked(IBinder activityToken, IBinder windowToken,
- IBinder appCallbackToken, boolean hasCallback, int flags) {
+ private Session createSessionByTokenLocked(@NonNull IBinder activityToken,
+ @Nullable IBinder windowToken, @NonNull IBinder appCallbackToken, boolean hasCallback,
+ int flags, @NonNull String packageName) {
final Session newSession = new Session(mContext, activityToken,
- windowToken, appCallbackToken, hasCallback, flags);
+ windowToken, appCallbackToken, hasCallback, flags, packageName);
mSessions.put(activityToken, newSession);
/*
@@ -351,7 +360,6 @@
* - display disclosure if needed
*/
try {
- // TODO(b/33197203): add MetricsLogger call
final Bundle receiverExtras = new Bundle();
receiverExtras.putBinder(EXTRA_ACTIVITY_TOKEN, activityToken);
final long identity = Binder.clearCallingIdentity();
@@ -371,7 +379,6 @@
void updateSessionLocked(IBinder activityToken, AutofillId autofillId, Rect bounds,
AutofillValue value, int flags) {
- // TODO(b/33197203): add MetricsLogger call
final Session session = mSessions.get(activityToken);
if (session == null) {
if (VERBOSE) {
@@ -595,6 +602,9 @@
private final IBinder mActivityToken;
private final IBinder mWindowToken;
+ /** Package name of the app that is auto-filled */
+ @NonNull private final String mPackageName;
+
@GuardedBy("mLock")
private final Map<AutofillId, ViewState> mViewStates = new ArrayMap<>();
@@ -634,15 +644,16 @@
* Flags used to start the session.
*/
private int mFlags;
-
- private Session(Context context, IBinder activityToken, IBinder windowToken,
- IBinder client, boolean hasCallback, int flags) {
+ private Session(@NonNull Context context, @NonNull IBinder activityToken,
+ @Nullable IBinder windowToken, @NonNull IBinder client, boolean hasCallback,
+ int flags, @NonNull String packageName) {
mRemoteFillService = new RemoteFillService(context,
mInfo.getServiceInfo().getComponentName(), mUserId, this);
mActivityToken = activityToken;
mWindowToken = windowToken;
mHasCallback = hasCallback;
mFlags = flags;
+ mPackageName = packageName;
mClient = IAutoFillManagerClient.Stub.asInterface(client);
try {
@@ -656,41 +667,82 @@
} catch (RemoteException e) {
Slog.w(TAG, "linkToDeath() on mClient failed: " + e);
}
+
+ mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_SESSION_STARTED, mPackageName);
}
// FillServiceCallbacks
@Override
- public void onFillRequestSuccess(FillResponse response) {
- // TODO(b/33197203): add MetricsLogger call
+ public void onFillRequestSuccess(@Nullable FillResponse response,
+ @NonNull String servicePackageName) {
if (response == null) {
+ // Nothing to be done, but need to notify client.
+ notifyUnavailableToClient();
removeSelf();
return;
}
+
+ if ((response.getDatasets() == null || response.getDatasets().isEmpty())
+ && response.getAuthentication() == null) {
+ // Response is "empty" from an UI point of view, need to notify client.
+ notifyUnavailableToClient();
+ }
synchronized (mLock) {
processResponseLocked(response);
}
+
+ LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_REQUEST))
+ .setType(MetricsProto.MetricsEvent.TYPE_SUCCESS)
+ .setPackageName(mPackageName)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
+ response.getDatasets() == null ? 0 : response.getDatasets().size())
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE,
+ servicePackageName);
+ mMetricsLogger.write(log);
}
// FillServiceCallbacks
@Override
- public void onFillRequestFailure(CharSequence message) {
- // TODO(b/33197203): add MetricsLogger call
+ public void onFillRequestFailure(@Nullable CharSequence message,
+ @NonNull String servicePackageName) {
+ LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_REQUEST))
+ .setType(MetricsProto.MetricsEvent.TYPE_FAILURE)
+ .setPackageName(mPackageName)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE,
+ servicePackageName);
+ mMetricsLogger.write(log);
+
getUiForShowing().showError(message);
removeSelf();
}
// FillServiceCallbacks
@Override
- public void onSaveRequestSuccess() {
- // TODO(b/33197203): add MetricsLogger call
+ public void onSaveRequestSuccess(@NonNull String servicePackageName) {
+ LogMaker log = (new LogMaker(
+ MetricsProto.MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST))
+ .setType(MetricsProto.MetricsEvent.TYPE_SUCCESS)
+ .setPackageName(mPackageName)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE,
+ servicePackageName);
+ mMetricsLogger.write(log);
+
// Nothing left to do...
removeSelf();
}
// FillServiceCallbacks
@Override
- public void onSaveRequestFailure(CharSequence message) {
- // TODO(b/33197203): add MetricsLogger call
+ public void onSaveRequestFailure(@Nullable CharSequence message,
+ @NonNull String servicePackageName) {
+ LogMaker log = (new LogMaker(
+ MetricsProto.MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST))
+ .setType(MetricsProto.MetricsEvent.TYPE_FAILURE)
+ .setPackageName(mPackageName)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE,
+ servicePackageName);
+ mMetricsLogger.write(log);
+
getUiForShowing().showError(message);
removeSelf();
}
@@ -773,6 +825,9 @@
Parcelable result = data.getParcelable(
AutofillManager.EXTRA_AUTHENTICATION_RESULT);
if (result instanceof FillResponse) {
+ mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_AUTHENTICATED,
+ mPackageName);
+
mCurrentResponse = (FillResponse) result;
processResponseLocked(mCurrentResponse);
} else if (result instanceof Dataset) {
@@ -894,7 +949,7 @@
if (atLeastOneChanged) {
getUiForShowing().showSaveUi(
mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()),
- saveInfo);
+ saveInfo, mPackageName);
return;
}
}
@@ -1034,7 +1089,7 @@
filterText = value.getTextValue().toString();
}
- getUiForShowing().showFillUi(filledId, response, bounds, filterText);
+ getUiForShowing().showFillUi(filledId, response, bounds, filterText, mPackageName);
}
private void notifyChangeToClient(AutofillId id, int event) {
@@ -1046,17 +1101,24 @@
}
}
+ private void notifyUnavailableToClient() {
+ if (mCurrentViewState == null) {
+ // TODO(b/33197203): temporary sanity check; should never happen
+ Slog.w(TAG, "notifyUnavailable(): mCurrentViewState is null");
+ return;
+ }
+ notifyChangeToClient(mCurrentViewState.mId, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
+ }
+
private void processResponseLocked(FillResponse response) {
if (DEBUG) {
Slog.d(TAG, "processResponseLocked(auth=" + response.getAuthentication()
+ "):" + response);
}
- // TODO(b/33197203): add MetricsLogger calls
-
if (mCurrentViewState == null) {
// TODO(b/33197203): temporary sanity check; should never happen
- Slog.w(TAG, "processResponseLocked(): mCurrentResponse is null");
+ Slog.w(TAG, "processResponseLocked(): mCurrentViewState is null");
return;
}
@@ -1188,6 +1250,9 @@
private void destroyLocked() {
mRemoteFillService.destroy();
mUi.setCallback(null, null);
+
+ mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_SESSION_FINISHED,
+ mPackageName);
}
private void removeSelf() {
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index b1cc89b..c41ac05 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -87,10 +87,10 @@
private PendingRequest mPendingRequest;
public interface FillServiceCallbacks {
- void onFillRequestSuccess(FillResponse response);
- void onFillRequestFailure(CharSequence message);
- void onSaveRequestSuccess();
- void onSaveRequestFailure(CharSequence message);
+ void onFillRequestSuccess(@Nullable FillResponse response, @NonNull String servicePackageName);
+ void onFillRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName);
+ void onSaveRequestSuccess(@NonNull String servicePackageName);
+ void onSaveRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName);
void onServiceDied(RemoteFillService service);
void onDisableSelf();
}
@@ -262,7 +262,7 @@
FillResponse response) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onFillRequestSuccess(response);
+ mCallbacks.onFillRequestSuccess(response, mComponentName.getPackageName());
}
});
}
@@ -271,7 +271,7 @@
CharSequence message) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onFillRequestFailure(message);
+ mCallbacks.onFillRequestFailure(message, mComponentName.getPackageName());
}
});
}
@@ -279,7 +279,7 @@
private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onSaveRequestSuccess();
+ mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName());
}
});
}
@@ -288,7 +288,7 @@
CharSequence message) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
- mCallbacks.onSaveRequestFailure(message);
+ mCallbacks.onSaveRequestFailure(message, mComponentName.getPackageName());
}
});
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 4f3446d..776fa1e 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.IntentSender;
import android.graphics.Rect;
+import android.metrics.LogMaker;
import android.os.Handler;
import android.os.IBinder;
import android.service.autofill.Dataset;
@@ -34,6 +35,8 @@
import android.view.autofill.AutofillId;
import android.widget.Toast;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.server.UiThread;
import java.io.PrintWriter;
@@ -60,6 +63,7 @@
private @Nullable IBinder mWindowToken;
private int mSaveTimeoutMs = (int) (5 * DateUtils.SECOND_IN_MILLIS);
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
public interface AutoFillUiCallback {
void authenticate(@NonNull IntentSender intent);
@@ -152,9 +156,17 @@
* @param response the current fill response
* @param anchorBounds bounds of the focused view
* @param filterText text of the view to be filled
+ * @param packageName package name of the activity that is filled
*/
public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response,
- @NonNull Rect anchorBounds, @Nullable String filterText) {
+ @NonNull Rect anchorBounds, @Nullable String filterText, @NonNull String packageName) {
+ LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_FILL_UI))
+ .setPackageName(packageName)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN,
+ filterText == null ? 0 : filterText.length())
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
+ response.getDatasets() == null ? 0 : response.getDatasets().size());
+
mHandler.post(() -> {
if (!hasCallback()) {
return;
@@ -164,6 +176,7 @@
mWindowToken, anchorBounds, filterText, new FillUi.Callback() {
@Override
public void onResponsePicked(FillResponse response) {
+ log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL);
hideFillUiUiThread();
if (mCallback != null) {
mCallback.authenticate(response.getAuthentication());
@@ -172,17 +185,25 @@
@Override
public void onDatasetPicked(Dataset dataset) {
+ log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
hideFillUiUiThread();
if (mCallback != null) {
mCallback.fill(dataset);
}
- // TODO(b/33197203): add MetricsLogger call
}
@Override
public void onCanceled() {
+ log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS);
hideFillUiUiThread();
- // TODO(b/33197203): add MetricsLogger call
+ }
+
+ @Override
+ public void onDestroy() {
+ if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
+ log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
+ }
+ mMetricsLogger.write(log);
}
});
mCallback.onEvent(focusedId, EVENT_INPUT_SHOWN);
@@ -192,7 +213,16 @@
/**
* Shows the UI asking the user to save for autofill.
*/
- public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info) {
+ public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info,
+ @NonNull String packageName) {
+ int numIds = 0;
+ numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
+ numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length;
+
+ LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_SAVE_UI))
+ .setPackageName(packageName).addTaggedData(
+ MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds);
+
mHandler.post(() -> {
if (!hasCallback()) {
return;
@@ -202,16 +232,16 @@
new SaveUi.OnSaveListener() {
@Override
public void onSave() {
+ log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
hideSaveUiUiThread();
if (mCallback != null) {
mCallback.save();
}
- // TODO(b/33197203): add MetricsLogger call
}
@Override
public void onCancel(IntentSender listener) {
- // TODO(b/33197203): add MetricsLogger call
+ log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS);
hideSaveUiUiThread();
if (listener != null) {
try {
@@ -225,6 +255,14 @@
mCallback.cancelSave();
}
}
+
+ @Override
+ public void onDestroy() {
+ if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
+ log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
+ }
+ mMetricsLogger.write(log);
+ }
}, mSaveTimeoutMs);
});
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index e420da2..a8c8752 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -51,6 +51,7 @@
void onResponsePicked(@NonNull FillResponse response);
void onDatasetPicked(@NonNull Dataset dataset);
void onCanceled();
+ void onDestroy();
}
private final Rect mAnchorBounds = new Rect();
@@ -205,6 +206,7 @@
public void destroy() {
throwIfDestroyed();
+ mCallback.onDestroy();
mWindow.hide();
mDestroyed = true;
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 3f409ad..644abe6 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -40,6 +40,7 @@
public interface OnSaveListener {
void onSave();
void onCancel(IntentSender listener);
+ void onDestroy();
}
private final Handler mHandler = UiThread.getHandler();
@@ -122,6 +123,7 @@
void destroy() {
throwIfDestroyed();
+ mListener.onDestroy();
mHandler.removeCallbacksAndMessages(mListener);
mDialog.dismiss();
mDestroyed = true;
diff --git a/services/core/java/com/android/server/BackgroundDexOptJobService.java b/services/core/java/com/android/server/BackgroundDexOptJobService.java
deleted file mode 100644
index 69e6ac5..0000000
--- a/services/core/java/com/android/server/BackgroundDexOptJobService.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
-
-import android.app.job.JobInfo;
-import android.app.job.JobParameters;
-import android.app.job.JobScheduler;
-import android.app.job.JobService;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.BatteryManager;
-import android.os.Environment;
-import android.os.ServiceManager;
-import android.os.storage.StorageManager;
-import android.util.ArraySet;
-import android.util.Log;
-import com.android.server.pm.PackageManagerService;
-
-import java.io.File;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.TimeUnit;
-
-public class BackgroundDexOptJobService extends JobService {
- private static final String TAG = "BackgroundDexOptJobService";
-
- private static final boolean DEBUG = false;
-
- private static final int JOB_IDLE_OPTIMIZE = 800;
- private static final int JOB_POST_BOOT_UPDATE = 801;
-
- private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG
- ? TimeUnit.MINUTES.toMillis(1)
- : TimeUnit.DAYS.toMillis(1);
-
- private static ComponentName sDexoptServiceName = new ComponentName(
- "android",
- BackgroundDexOptJobService.class.getName());
-
- /**
- * Set of failed packages remembered across job runs.
- */
- static final ArraySet<String> sFailedPackageNames = new ArraySet<String>();
-
- /**
- * Atomics set to true if the JobScheduler requests an abort.
- */
- final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false);
- final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false);
-
- /**
- * Atomic set to true if one job should exit early because another job was started.
- */
- final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
-
- private final File mDataDir = Environment.getDataDirectory();
-
- public static void schedule(Context context) {
- JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-
- // Schedule a one-off job which scans installed packages and updates
- // out-of-date oat files.
- js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName)
- .setMinimumLatency(TimeUnit.MINUTES.toMillis(1))
- .setOverrideDeadline(TimeUnit.MINUTES.toMillis(1))
- .build());
-
- // Schedule a daily job which scans installed packages and compiles
- // those with fresh profiling data.
- js.schedule(new JobInfo.Builder(JOB_IDLE_OPTIMIZE, sDexoptServiceName)
- .setRequiresDeviceIdle(true)
- .setRequiresCharging(true)
- .setPeriodic(IDLE_OPTIMIZATION_PERIOD)
- .build());
-
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Jobs scheduled");
- }
- }
-
- public static void notifyPackageChanged(String packageName) {
- // The idle maintanance job skips packages which previously failed to
- // compile. The given package has changed and may successfully compile
- // now. Remove it from the list of known failing packages.
- synchronized (sFailedPackageNames) {
- sFailedPackageNames.remove(packageName);
- }
- }
-
- // Returns the current battery level as a 0-100 integer.
- private int getBatteryLevel() {
- IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
- Intent intent = registerReceiver(null, filter);
- int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
- int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
-
- if (level < 0 || scale <= 0) {
- // Battery data unavailable. This should never happen, so assume the worst.
- return 0;
- }
-
- return (100 * level / scale);
- }
-
- private long getLowStorageThreshold() {
- @SuppressWarnings("deprecation")
- final long lowThreshold = StorageManager.from(this).getStorageLowBytes(mDataDir);
- if (lowThreshold == 0) {
- Log.e(TAG, "Invalid low storage threshold");
- }
-
- return lowThreshold;
- }
-
- private boolean runPostBootUpdate(final JobParameters jobParams,
- final PackageManagerService pm, final ArraySet<String> pkgs) {
- if (mExitPostBootUpdate.get()) {
- // This job has already been superseded. Do not start it.
- return false;
- }
- new Thread("BackgroundDexOptService_PostBootUpdate") {
- @Override
- public void run() {
- postBootUpdate(jobParams, pm, pkgs);
- }
-
- }.start();
- return true;
- }
-
- private void postBootUpdate(JobParameters jobParams, PackageManagerService pm,
- ArraySet<String> pkgs) {
- // Load low battery threshold from the system config. This is a 0-100 integer.
- final int lowBatteryThreshold = getResources().getInteger(
- com.android.internal.R.integer.config_lowBatteryWarningLevel);
- final long lowThreshold = getLowStorageThreshold();
-
- mAbortPostBootUpdate.set(false);
-
- for (String pkg : pkgs) {
- if (mAbortPostBootUpdate.get()) {
- // JobScheduler requested an early abort.
- return;
- }
- if (mExitPostBootUpdate.get()) {
- // Different job, which supersedes this one, is running.
- break;
- }
- if (getBatteryLevel() < lowBatteryThreshold) {
- // Rather bail than completely drain the battery.
- break;
- }
- long usableSpace = mDataDir.getUsableSpace();
- if (usableSpace < lowThreshold) {
- // Rather bail than completely fill up the disk.
- Log.w(TAG, "Aborting background dex opt job due to low storage: " +
- usableSpace);
- break;
- }
-
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Updating package " + pkg);
- }
-
- // Update package if needed. Note that there can be no race between concurrent
- // jobs because PackageDexOptimizer.performDexOpt is synchronized.
-
- // checkProfiles is false to avoid merging profiles during boot which
- // might interfere with background compilation (b/28612421).
- // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
- // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
- // trade-off worth doing to save boot time work.
- pm.performDexOpt(pkg,
- /* checkProfiles */ false,
- PackageManagerService.REASON_BOOT,
- /* force */ false);
- }
- // Ran to completion, so we abandon our timeslice and do not reschedule.
- jobFinished(jobParams, /* reschedule */ false);
- }
-
- private boolean runIdleOptimization(final JobParameters jobParams,
- final PackageManagerService pm, final ArraySet<String> pkgs) {
- new Thread("BackgroundDexOptService_IdleOptimization") {
- @Override
- public void run() {
- idleOptimization(jobParams, pm, pkgs);
- }
- }.start();
- return true;
- }
-
- private void idleOptimization(JobParameters jobParams, PackageManagerService pm,
- ArraySet<String> pkgs) {
- Log.i(TAG, "Performing idle optimizations");
- // If post-boot update is still running, request that it exits early.
- mExitPostBootUpdate.set(true);
-
- mAbortIdleOptimization.set(false);
-
- final long lowThreshold = getLowStorageThreshold();
- for (String pkg : pkgs) {
- if (mAbortIdleOptimization.get()) {
- // JobScheduler requested an early abort.
- return;
- }
-
- synchronized (sFailedPackageNames) {
- if (sFailedPackageNames.contains(pkg)) {
- // Skip previously failing package
- continue;
- }
- }
-
- long usableSpace = mDataDir.getUsableSpace();
- if (usableSpace < lowThreshold) {
- // Rather bail than completely fill up the disk.
- Log.w(TAG, "Aborting background dex opt job due to low storage: " +
- usableSpace);
- break;
- }
-
- // Conservatively add package to the list of failing ones in case performDexOpt
- // never returns.
- synchronized (sFailedPackageNames) {
- sFailedPackageNames.add(pkg);
- }
- // Optimize package if needed. Note that there can be no race between
- // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
- if (pm.performDexOpt(pkg,
- /* checkProfiles */ true,
- PackageManagerService.REASON_BACKGROUND_DEXOPT,
- /* force */ false)) {
- // Dexopt succeeded, remove package from the list of failing ones.
- synchronized (sFailedPackageNames) {
- sFailedPackageNames.remove(pkg);
- }
- }
- }
- // Ran to completion, so we abandon our timeslice and do not reschedule.
- jobFinished(jobParams, /* reschedule */ false);
- }
-
- @Override
- public boolean onStartJob(JobParameters params) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "onStartJob");
- }
-
- // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from
- // the checks above. This check is not "live" - the value is determined by a background
- // restart with a period of ~1 minute.
- PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
- if (pm.isStorageLow()) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Low storage, skipping this run");
- }
- return false;
- }
-
- final ArraySet<String> pkgs = pm.getOptimizablePackages();
- if (pkgs == null || pkgs.isEmpty()) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "No packages to optimize");
- }
- return false;
- }
-
- if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
- return runPostBootUpdate(params, pm, pkgs);
- } else {
- return runIdleOptimization(params, pm, pkgs);
- }
- }
-
- @Override
- public boolean onStopJob(JobParameters params) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "onStopJob");
- }
-
- if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
- mAbortPostBootUpdate.set(true);
- } else {
- mAbortIdleOptimization.set(true);
- }
- return false;
- }
-}
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 34c73d2..c946d09 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -1488,7 +1488,7 @@
return VerifyCredentialResponse.OK;
}
- if (TextUtils.isEmpty(credential)) {
+ if (storedHash == null || TextUtils.isEmpty(credential)) {
return VerifyCredentialResponse.ERROR;
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3667ecd..8e6310f 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2721,7 +2721,7 @@
*/
@Override
public int getPasswordType() {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"no permission to access the crypt keeper");
waitForReady();
@@ -2747,7 +2747,7 @@
*/
@Override
public void setField(String field, String contents) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"no permission to access the crypt keeper");
waitForReady();
@@ -2767,7 +2767,7 @@
*/
@Override
public String getField(String field) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"no permission to access the crypt keeper");
waitForReady();
@@ -2793,7 +2793,7 @@
*/
@Override
public boolean isConvertibleToFBE() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"no permission to access the crypt keeper");
waitForReady();
@@ -2809,7 +2809,7 @@
@Override
public String getPassword() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"only keyguard can retrieve password");
if (!isReady()) {
@@ -2834,7 +2834,7 @@
@Override
public void clearPassword() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"only keyguard can clear password");
if (!isReady()) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index accae0d..f954f75 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -35,7 +35,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityThread;
-import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.INotificationManager;
import android.app.Notification;
@@ -64,7 +63,6 @@
import android.content.pm.UserInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteStatement;
-import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -80,7 +78,6 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -113,7 +110,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -158,6 +154,11 @@
public void onUnlockUser(int userHandle) {
mService.onUnlockUser(userHandle);
}
+
+ @Override
+ public void onCleanupUser(int userHandle) {
+ mService.onCleanupUser(userHandle);
+ }
}
final Context mContext;
@@ -303,18 +304,6 @@
}
}, intentFilter);
- IntentFilter userFilter = new IntentFilter();
- userFilter.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_USER_REMOVED.equals(action)) {
- onUserRemoved(intent);
- }
- }
- }, UserHandle.ALL, userFilter, null, null);
-
injector.addLocalService(new AccountManagerInternalImpl());
// Need to cancel account request notifications if the update/install can access the account
@@ -1133,16 +1122,12 @@
}
}
- private void onUserRemoved(Intent intent) {
- int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId < 1) return;
-
+ private void onCleanupUser(int userId) {
+ Log.i(TAG, "onCleanupUser " + userId);
UserAccounts accounts;
- boolean userUnlocked;
synchronized (mUsers) {
accounts = mUsers.get(userId);
mUsers.remove(userId);
- userUnlocked = mLocalUnlockedUsers.get(userId);
mLocalUnlockedUsers.delete(userId);
}
if (accounts != null) {
@@ -1150,18 +1135,6 @@
accounts.accountsDb.close();
}
}
- Log.i(TAG, "Removing database files for user " + userId);
- File dbFile = new File(mInjector.getDeDatabaseName(userId));
-
- AccountsDb.deleteDbFileWarnIfFailed(dbFile);
- // Remove CE file if user is unlocked, or FBE is not enabled
- boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated();
- if (!fbeEnabled || userUnlocked) {
- File ceDb = new File(mInjector.getCeDatabaseName(userId));
- if (ceDb.exists()) {
- AccountsDb.deleteDbFileWarnIfFailed(ceDb);
- }
- }
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index ebbce02..918747b 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -251,7 +251,8 @@
* ActivityManagerInternal.APP_TRANSITION_* reasons.
*/
void notifyTransitionStarting(SparseIntArray stackIdReasons) {
- if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
+ // TODO (b/36339388): Figure out why stackIdReasons can be null
+ if (stackIdReasons == null || !isAnyTransitionActive() || mLoggedTransitionStarting) {
return;
}
mCurrentTransitionDelayMs = calculateCurrentDelay();
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 2e26bed..2b2471b 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1953,11 +1953,6 @@
}
void setRequestedOrientation(int requestedOrientation) {
- if (task != null && (!task.mFullscreen || !task.getStack().mFullscreen)) {
- // Fixed screen orientation isn't supported when activities aren't in full screen mode.
- return;
- }
-
final int displayId = getDisplayId();
final Configuration displayConfig =
mStackSupervisor.getDisplayOverrideConfiguration(displayId);
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 2787895..dd3d4e0 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1152,17 +1152,14 @@
skip = true;
}
}
- final boolean visibleToInstantApps =
- (r.intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
if (!skip && info.activityInfo.applicationInfo.isInstantApp()
- && !visibleToInstantApps
&& r.callingUid != info.activityInfo.applicationInfo.uid) {
Slog.w(TAG, "Instant App Denial: receiving "
+ r.intent
+ " to " + component.flattenToShortString()
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")"
- + " not specifying FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS");
+ + " Instant Apps do not support manifest receivers");
skip = true;
}
if (!skip && r.callerInstantApp
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
index dec2f77..8c6430c 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity.tethering;
+import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
+
import android.net.INetd;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -48,7 +50,6 @@
public class IPv6TetheringInterfaceServices {
private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName();
private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
- private static final int RFC7421_IP_PREFIX_LENGTH = 64;
private final String mIfName;
private final INetworkManagementService mNMService;
@@ -124,7 +125,7 @@
params.hasDefaultRoute = v6only.hasIPv6DefaultRoute();
for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
- if (linkAddr.getPrefixLength() != RFC7421_IP_PREFIX_LENGTH) continue;
+ if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
final IpPrefix prefix = new IpPrefix(
linkAddr.getAddress(), linkAddr.getPrefixLength());
@@ -206,7 +207,7 @@
for (Inet6Address dns : deprecatedDnses) {
final String dnsString = dns.getHostAddress();
try {
- netd.interfaceDelAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH);
+ netd.interfaceDelAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH);
} catch (ServiceSpecificException | RemoteException e) {
Log.e(TAG, "Failed to remove local dns IP: " + dnsString, e);
}
@@ -223,7 +224,7 @@
for (Inet6Address dns : addedDnses) {
final String dnsString = dns.getHostAddress();
try {
- netd.interfaceAddAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH);
+ netd.interfaceAddAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH);
} catch (ServiceSpecificException | RemoteException e) {
Log.e(TAG, "Failed to add local dns IP: " + dnsString, e);
newDnses.remove(dns);
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 3262151..bdba64f 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -97,7 +97,6 @@
static final String TAG = "FingerprintService";
static final boolean DEBUG = true;
private static final String FP_DATA_DIR = "fpdata";
- private static final String FINGERPRINT_HIDL = "fingerprint_hal";
private static final int MSG_USER_SWITCHING = 10;
private static final String ACTION_LOCKOUT_RESET =
"com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
@@ -219,7 +218,7 @@
public synchronized IBiometricsFingerprint getFingerprintDaemon() {
if (mDaemon == null) {
try {
- mDaemon = IBiometricsFingerprint.getService(FINGERPRINT_HIDL);
+ mDaemon = IBiometricsFingerprint.getService();
} catch (java.util.NoSuchElementException e) {
// Service doesn't exist or cannot be opened. Logged below.
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7285a4c..8280946 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -159,6 +159,8 @@
import libcore.io.IoUtils;
+import com.google.android.collect.Lists;
+
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
@@ -1658,8 +1660,7 @@
public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
String channelId, boolean includeDeleted) {
checkCallerIsSystem();
- return mRankingHelper.getNotificationChannel
- (pkg, uid, channelId, includeDeleted);
+ return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
}
@Override
@@ -1675,6 +1676,27 @@
}
@Override
+ public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
+ String pkg) {
+ checkCallerIsSystemOrSameApp(pkg);
+ return new ParceledListSlice<>(new ArrayList(
+ mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
+ }
+
+ @Override
+ public void deleteNotificationChannelGroup(String pkg, String channelGroupId) {
+ checkCallerIsSystemOrSameApp(pkg);
+
+ List<String> deletedChannelIds = mRankingHelper.deleteNotificationChannelGroup(
+ pkg, Binder.getCallingUid(), channelGroupId);
+ for (int i = 0; i < deletedChannelIds.size(); i++) {
+ cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannelIds.get(i), 0, 0, true,
+ UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
+ }
+ savePolicyFile();
+ }
+
+ @Override
public void updateNotificationChannelForPackage(String pkg, int uid,
NotificationChannel channel) {
enforceSystemOrSystemUI("Caller not system or systemui");
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index e239164..02f92fe 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -15,8 +15,6 @@
*/
package com.android.server.notification;
-import static android.app.NotificationManager.IMPORTANCE_NONE;
-
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -654,8 +652,6 @@
@Override
public void deleteNotificationChannel(String pkg, int uid, String channelId) {
- Preconditions.checkNotNull(pkg);
- Preconditions.checkNotNull(channelId);
Record r = getRecord(pkg, uid);
if (r == null) {
return;
@@ -667,6 +663,7 @@
LogMaker lm = getChannelLog(channel, pkg);
lm.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
MetricsLogger.action(lm);
+ updateConfig();
}
@Override
@@ -679,6 +676,7 @@
return;
}
r.channels.remove(channelId);
+ updateConfig();
}
@Override
@@ -695,6 +693,7 @@
r.channels.remove(key);
}
}
+ updateConfig();
}
public NotificationChannelGroup getNotificationChannelGroup(String groupId, String pkg,
@@ -719,12 +718,15 @@
final NotificationChannel nc = r.channels.valueAt(i);
if (includeDeleted || !nc.isDeleted()) {
if (nc.getGroup() != null) {
- NotificationChannelGroup ncg = groups.get(nc.getGroup());
- if (ncg == null ) {
- ncg = r.groups.get(nc.getGroup()).clone();
- groups.put(nc.getGroup(), ncg);
+ if (r.groups.get(nc.getGroup()) != null) {
+ NotificationChannelGroup ncg = groups.get(nc.getGroup());
+ if (ncg == null) {
+ ncg = r.groups.get(nc.getGroup()).clone();
+ groups.put(nc.getGroup(), ncg);
+
+ }
+ ncg.addChannel(nc);
}
- ncg.addChannel(nc);
} else {
nonGrouped.addChannel(nc);
}
@@ -736,8 +738,29 @@
return new ParceledListSlice<>(new ArrayList<>(groups.values()));
}
+ public List<String> deleteNotificationChannelGroup(String pkg, int uid,
+ String groupId) {
+ List<String> deletedChannelIds = new ArrayList<>();
+ Record r = getRecord(pkg, uid);
+ if (r == null || TextUtils.isEmpty(groupId)) {
+ return deletedChannelIds;
+ }
+
+ r.groups.remove(groupId);
+
+ int N = r.channels.size();
+ for (int i = 0; i < N; i++) {
+ final NotificationChannel nc = r.channels.valueAt(i);
+ if (groupId.equals(nc.getGroup())) {
+ nc.setDeleted(true);
+ deletedChannelIds.add(nc.getId());
+ }
+ }
+ updateConfig();
+ return deletedChannelIds;
+ }
+
@Override
- @VisibleForTesting
public Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
int uid) {
Record r = getRecord(pkg, uid);
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 7aa96cf..d8900c0 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -49,8 +49,6 @@
private static final boolean DEBUG = false;
- private static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR;
-
private static final int JOB_IDLE_OPTIMIZE = 800;
private static final int JOB_POST_BOOT_UPDATE = 801;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4ac1cce..fb3080b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -260,7 +260,6 @@
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.AttributeCache;
-import com.android.server.BackgroundDexOptJobService;
import com.android.server.DeviceIdleController;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
@@ -272,6 +271,7 @@
import com.android.server.SystemServerInitThreadPool;
import com.android.server.Watchdog;
import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.pm.BackgroundDexOptService;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.PermissionsState.PermissionState;
import com.android.server.pm.Settings.DatabaseVersion;
@@ -2038,12 +2038,15 @@
final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
>= Build.VERSION_CODES.M;
+ final boolean instantApp = isInstantApp(pkg.packageName, userId);
+
for (String permission : pkg.requestedPermissions) {
final BasePermission bp;
synchronized (mPackages) {
bp = mSettings.mPermissions.get(permission);
}
if (bp != null && (bp.isRuntime() || bp.isDevelopment())
+ && (!instantApp || bp.isInstant())
&& (grantedPermissions == null
|| ArrayUtils.contains(grantedPermissions, permission))) {
final int flags = permissionsState.getPermissionFlags(permission, userId);
@@ -16850,11 +16853,11 @@
mDexManager.isUsedByOtherApps(pkg.packageName));
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- // Notify BackgroundDexOptJobService that the package has been changed.
+ // Notify BackgroundDexOptService that the package has been changed.
// If this is an update of a package which used to fail to compile,
// BDOS will remove it from its blacklist.
// TODO: Layering violation
- BackgroundDexOptJobService.notifyPackageChanged(pkg.packageName);
+ BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
}
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index a7349fc..751d9af 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -147,6 +147,8 @@
return runSetHomeActivity();
case "get-privapp-permissions":
return runGetPrivappPermissions();
+ case "has-feature":
+ return runHasFeature();
default:
return handleDefaultCommands(cmd);
}
@@ -1268,6 +1270,28 @@
return 0;
}
+ private int runHasFeature() {
+ final PrintWriter err = getErrPrintWriter();
+ final String featureName = getNextArg();
+ if (featureName == null) {
+ err.println("Error: expected FEATURE name");
+ return 1;
+ }
+ final String versionString = getNextArg();
+ try {
+ final int version = (versionString == null) ? 0 : Integer.parseInt(versionString);
+ final boolean hasFeature = mInterface.hasSystemFeature(featureName, version);
+ getOutPrintWriter().println(hasFeature);
+ return hasFeature ? 0 : 1;
+ } catch (NumberFormatException e) {
+ err.println("Error: illegal version number " + versionString);
+ return 1;
+ } catch (RemoteException e) {
+ err.println(e.toString());
+ return 1;
+ }
+ }
+
private static String checkAbiArgument(String abi) {
if (TextUtils.isEmpty(abi)) {
throw new IllegalArgumentException("Missing ABI argument");
@@ -1649,6 +1673,9 @@
pw.println(" Unsuspends the specified package (as user).");
pw.println(" set-home-activity [--user USER_ID] TARGET-COMPONENT");
pw.println(" set the default home activity (aka launcher).");
+ pw.println(" has-feature FEATURE_NAME [version]");
+ pw.println(" prints true and returns exit status 0 when system has a FEATURE_NAME,");
+ pw.println(" otherwise prints false and returns exit status 1");
pw.println();
Intent.printIntentArgsHelp(pw , "");
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b9fcf4e..1f97d7d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1810,8 +1810,8 @@
if (type == XmlPullParser.START_TAG) {
if (parser.getName().equals(TAG_RESTRICTIONS)) {
synchronized (mGuestRestrictions) {
- mGuestRestrictions.putAll(
- UserRestrictionsUtils.readRestrictions(parser));
+ UserRestrictionsUtils
+ .readRestrictions(parser, mGuestRestrictions);
}
}
break;
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 36eba8e..cb2ed6e 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -207,6 +207,7 @@
}
public static void readRestrictions(XmlPullParser parser, Bundle restrictions) {
+ restrictions.clear();
for (String key : USER_RESTRICTIONS) {
final String value = parser.getAttributeValue(null, key);
if (value != null) {
diff --git a/services/core/java/com/android/server/vr/CompatibilityDisplay.java b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
index 5e17daa..8f95cc7 100644
--- a/services/core/java/com/android/server/vr/CompatibilityDisplay.java
+++ b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
@@ -1,6 +1,8 @@
package com.android.server.vr;
+import static android.view.Display.INVALID_DISPLAY;
+
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -86,10 +88,8 @@
startVirtualDisplay();
}
} else {
- // TODO: Remove conditional when launching apps 2D doesn't force VrMode to stop.
- if (!DEBUG) {
- stopVirtualDisplay();
- }
+ // Stop virtual display to test exit condition
+ stopVirtualDisplay();
}
}
@@ -138,6 +138,19 @@
}
}
+ public int getVirtualDisplayId() {
+ synchronized(vdLock) {
+ if (mVirtualDisplay != null) {
+ int virtualDisplayId = mVirtualDisplay.getDisplay().getDisplayId();
+ if (DEBUG) {
+ Log.e(TAG, "VD id: " + virtualDisplayId);
+ }
+ return virtualDisplayId;
+ }
+ }
+ return INVALID_DISPLAY;
+ }
+
private void startVirtualDisplay() {
if (DEBUG) {
Log.d(TAG, "Request to start VD, DM:" + mDisplayManager);
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 58e4bdc..210aa44 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -90,6 +90,15 @@
public abstract void setPersistentVrModeEnabled(boolean enabled);
/**
+ * Return {@link android.view.Display.INVALID_DISPLAY} if there exists no virtual display
+ * currently or the display id of the current virtual display.
+ *
+ * @return {@link android.view.Display.INVALID_DISPLAY} if there is no virtual display
+ * currently, else return the display id of the virtual display
+ */
+ public abstract int getCompatibilityDisplayId();
+
+ /**
* Adds listener that reports state changes to persistent VR mode.
*/
public abstract void addPersistentVrModeStateListener(PersistentVrStateListener listener);
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 8a23173..a00115c 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -15,6 +15,8 @@
*/
package com.android.server.vr;
+import static android.view.Display.INVALID_DISPLAY;
+
import android.Manifest;
import android.app.ActivityManager;
import android.app.AppOpsManager;
@@ -392,6 +394,11 @@
}
@Override
+ public int getCompatibilityDisplayId() {
+ return VrManagerService.this.getCompatibilityDisplayId();
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
@@ -495,6 +502,11 @@
}
@Override
+ public int getCompatibilityDisplayId() {
+ return VrManagerService.this.getCompatibilityDisplayId();
+ }
+
+ @Override
public void addPersistentVrModeStateListener(PersistentVrStateListener listener) {
VrManagerService.this.addPersistentVrModeStateListener(listener);
}
@@ -1054,6 +1066,14 @@
}
}
+ private int getCompatibilityDisplayId() {
+ if (mCompatibilityDisplay != null) {
+ return mCompatibilityDisplay.getVirtualDisplayId();
+ }
+ Slog.w(TAG, "CompatibilityDisplay is null!");
+ return INVALID_DISPLAY;
+ }
+
private void setPersistentModeAndNotifyListenersLocked(boolean enabled) {
if (mPersistentVrModeEnabled == enabled) {
return;
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index ac95db5..b5ed266 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -65,6 +65,7 @@
libinputflinger \
libinputservice \
libsensorservice \
+ libsensorservicehidl \
libskia \
libgui \
libusbhost \
@@ -88,5 +89,6 @@
android.hardware.tv.input@1.0 \
android.hardware.vibrator@1.0 \
android.hardware.vr@1.0 \
+ android.frameworks.sensorservice@1.0 \
-LOCAL_STATIC_LIBRARIES += libscrypt_static
\ No newline at end of file
+LOCAL_STATIC_LIBRARIES += libscrypt_static
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 3120af5..8ad88ed 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -17,7 +17,10 @@
#include <jni.h>
#include <JNIHelp.h>
+#include <hidl/HidlTransportSupport.h>
+
#include <sensorservice/SensorService.h>
+#include <sensorservicehidl/SensorManager.h>
#include <cutils/properties.h>
#include <utils/Log.h>
@@ -32,6 +35,21 @@
if (strcmp(propBuf, "1") == 0) {
SensorService::instantiate();
}
+
+}
+
+static void android_server_SystemServer_startHidlServices(JNIEnv* /* env */, jobject /* clazz */) {
+ using ::android::frameworks::sensorservice::V1_0::ISensorManager;
+ using ::android::frameworks::sensorservice::V1_0::implementation::SensorManager;
+ using ::android::hardware::configureRpcThreadpool;
+
+ configureRpcThreadpool(1, false /* callerWillJoin */);
+ sp<ISensorManager> sensorService = new SensorManager();
+ status_t err = sensorService->registerAsService();
+ if (err != OK) {
+ ALOGE("Cannot register ::android::frameworks::sensorservice::V1_0::"
+ "implementation::SensorManager: %d", err);
+ }
}
/*
@@ -40,6 +58,7 @@
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },
+ { "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices },
};
int register_android_server_SystemServer(JNIEnv* env)
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a8423e2..e6e0242 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -86,6 +86,7 @@
import com.android.server.om.OverlayManagerService;
import com.android.server.os.DeviceIdentifiersPolicyService;
import com.android.server.os.SchedulingPolicyService;
+import com.android.server.pm.BackgroundDexOptService;
import com.android.server.pm.Installer;
import com.android.server.pm.LauncherAppsService;
import com.android.server.pm.OtaDexoptService;
@@ -235,16 +236,24 @@
private final boolean mRuntimeRestart;
private static final String START_SENSOR_SERVICE = "StartSensorService";
+ private static final String START_HIDL_SERVICES = "StartHidlServices";
+
+
private Future<?> mSensorServiceStart;
private Future<?> mZygotePreload;
-
/**
* Start the sensor service. This is a blocking call and can take time.
*/
private static native void startSensorService();
/**
+ * Start all HIDL services that are run inside the system server. This
+ * may take some time.
+ */
+ private static native void startHidlServices();
+
+ /**
* The main entry point from zygote.
*/
public static void main(String[] args) {
@@ -610,6 +619,7 @@
startSensorService();
traceLog.traceEnd();
}, START_SENSOR_SERVICE);
+
}
/**
@@ -637,6 +647,14 @@
traceBeginAndSlog("StartWebViewUpdateService");
mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
traceEnd();
+
+ // Start receiving calls from HIDL services. Start in in a separate thread
+ // because it need to connect to SensorManager.
+ SystemServerInitThreadPool.get().submit(() -> {
+ traceBeginAndSlog(START_HIDL_SERVICES);
+ startHidlServices();
+ traceEnd();
+ }, START_HIDL_SERVICES);
}
/**
@@ -1428,11 +1446,11 @@
traceEnd();
}
- traceBeginAndSlog("StartBackgroundDexOptJobService");
+ traceBeginAndSlog("StartBackgroundDexOptService");
try {
- BackgroundDexOptJobService.schedule(context);
+ BackgroundDexOptService.schedule(context);
} catch (Throwable e) {
- reportWtf("starting StartBackgroundDexOptJobService", e);
+ reportWtf("starting StartBackgroundDexOptService", e);
}
traceEnd();
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 3e3a19b..c670782 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -16,6 +16,8 @@
package android.net.ip;
+import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
+
import com.android.internal.util.MessageUtils;
import com.android.internal.util.WakeupMessage;
@@ -42,6 +44,7 @@
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.os.SystemClock;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
@@ -1028,15 +1031,36 @@
return true;
}
- private boolean startIPv6() {
- // Set privacy extensions.
+ private void enableInterfaceIPv6PrivacyExtensions() {
final String PREFER_TEMPADDRS = "2";
+ NetdService.run((INetd netd) -> {
+ netd.setProcSysNet(
+ INetd.IPV6, INetd.CONF, mInterfaceName, "use_tempaddr", PREFER_TEMPADDRS);
+ });
+ }
+
+ private void setInterfaceIPv6RaRtInfoMaxPlen(int plen) {
+ // Setting RIO max plen is best effort. Catch and ignore most exceptions.
try {
NetdService.run((INetd netd) -> {
- netd.setProcSysNet(
- INetd.IPV6, INetd.CONF, mInterfaceName, "use_tempaddr",
- PREFER_TEMPADDRS);
- });
+ netd.setProcSysNet(
+ INetd.IPV6, INetd.CONF, mInterfaceName, "accept_ra_rt_info_max_plen",
+ Integer.toString(plen));
+ });
+ } catch (ServiceSpecificException e) {
+ // Old kernel versions without support for RIOs do not export accept_ra_rt_info_max_plen
+ // in the /proc filesystem. If the kernel supports RIOs we should never see any other
+ // type of error.
+ if (e.errorCode != OsConstants.ENOENT) {
+ logError("unexpected error setting accept_ra_rt_info_max_plen %s", e);
+ }
+ }
+ }
+
+ private boolean startIPv6() {
+ try {
+ enableInterfaceIPv6PrivacyExtensions();
+ setInterfaceIPv6RaRtInfoMaxPlen(RFC7421_PREFIX_LENGTH);
mNwService.enableIpv6(mInterfaceName);
} catch (IllegalStateException|RemoteException|ServiceSpecificException e) {
logError("Unable to change interface settings: %s", e);
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 362f757..26f3050 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -97,6 +97,7 @@
public static final int IPV6_SRC_ADDR_OFFSET = 8;
public static final int IPV6_DST_ADDR_OFFSET = 24;
public static final int IPV6_ADDR_LEN = 16;
+ public static final int RFC7421_PREFIX_LENGTH = 64;
/**
* ICMPv6 constants.
diff --git a/services/tests/notification/Android.mk b/services/tests/notification/Android.mk
index de9553a..a5d5570 100644
--- a/services/tests/notification/Android.mk
+++ b/services/tests/notification/Android.mk
@@ -30,6 +30,7 @@
LOCAL_JACK_FLAGS := --multi-dex native
LOCAL_PACKAGE_NAME := FrameworksNotificationTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index b538453..27b9a88 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -854,6 +854,43 @@
}
@Test
+ public void testDeleteGroup() throws Exception {
+ NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted");
+ NotificationChannelGroup deleted = new NotificationChannelGroup("totally", "deleted");
+ NotificationChannel nonGroupedNonDeletedChannel =
+ new NotificationChannel("no group", "so not deleted", IMPORTANCE_HIGH);
+ NotificationChannel groupedButNotDeleted =
+ new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT);
+ groupedButNotDeleted.setGroup("not");
+ NotificationChannel groupedAndDeleted =
+ new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT);
+ groupedAndDeleted.setGroup("totally");
+
+ mHelper.createNotificationChannelGroup(pkg, uid, notDeleted, true);
+ mHelper.createNotificationChannelGroup(pkg, uid, deleted, true);
+ mHelper.createNotificationChannel(pkg, uid, nonGroupedNonDeletedChannel, true);
+ mHelper.createNotificationChannel(pkg, uid, groupedAndDeleted, true);
+ mHelper.createNotificationChannel(pkg, uid, groupedButNotDeleted, true);
+
+ mHelper.deleteNotificationChannelGroup(pkg, uid, deleted.getId());
+
+ assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), pkg, uid));
+ assertNotNull(mHelper.getNotificationChannelGroup(notDeleted.getId(), pkg, uid));
+
+ assertNull(mHelper.getNotificationChannel(pkg, uid, groupedAndDeleted.getId(), false));
+ compareChannels(groupedAndDeleted,
+ mHelper.getNotificationChannel(pkg, uid, groupedAndDeleted.getId(), true));
+
+ compareChannels(groupedButNotDeleted,
+ mHelper.getNotificationChannel(pkg, uid, groupedButNotDeleted.getId(), false));
+ compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel(
+ pkg, uid, nonGroupedNonDeletedChannel.getId(), false));
+
+ // notDeleted
+ assertEquals(1, mHelper.getNotificationChannelGroups(pkg, uid).size());
+ }
+
+ @Test
public void testOnPackageChanged_packageRemoval() throws Exception {
// Deleted
NotificationChannel channel1 =
@@ -889,7 +926,7 @@
mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid});
- assertEquals(0, mHelper.getNotificationChannelGroups(pkg, uid, true).getList().size());
+ assertEquals(0, mHelper.getNotificationChannelGroups(pkg, uid).size());
}
@Test
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 15c61f6..2a8f4a3 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -30,6 +30,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksServicesTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 9f50a2c..921e0e3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -126,8 +126,6 @@
}
@Test
- @Ignore
- // TODO(b/35034729): Need to fix before re-enabling
public void testLandscapeSeascapeRotationByPolicy() throws Exception {
// Some plumbing to get the service ready for rotation updates.
sWm.mDisplayReady = true;
@@ -145,15 +143,20 @@
appWindowToken.addWindow(appWindow);
// Set initial orientation and update.
- ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = Surface.ROTATION_90;
- sWm.updateRotation(false, false);
+ performRotation(Surface.ROTATION_90);
appWindow.resizeReported = false;
// Update the rotation to perform 180 degree rotation and check that resize was reported.
- ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = Surface.ROTATION_270;
- sWm.updateRotation(false, false);
- sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+ performRotation(Surface.ROTATION_270);
assertTrue(appWindow.resizeReported);
appWindow.removeImmediately();
}
+
+ private void performRotation(int rotationToReport) {
+ ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = rotationToReport;
+ sWm.updateRotation(false, false);
+ // Simulate animator finishing orientation change
+ sWm.mRoot.mOrientationChangeComplete = true;
+ sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 911050a..65efd9c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -71,7 +71,10 @@
static TestWindowManagerPolicy sPolicy = null;
private final static IWindow sIWindow = new TestIWindow();
private final static Session sMockSession = mock(Session.class);
- private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1;
+ // The default display is removed in {@link #setUp} and then we iterate over all displays to
+ // make sure we don't collide with any existing display. If we run into no other display, the
+ // added display should be treated as default.
+ private static int sNextDisplayId = Display.DEFAULT_DISPLAY;
static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
private static int sNextTaskId = 0;
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 40bdaa5..03d8241 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -25,8 +25,8 @@
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.midi.MidiDeviceInfo;
-import android.os.FileObserver;
import android.os.Bundle;
+import android.os.FileObserver;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -41,10 +41,7 @@
import libcore.io.IoUtils;
import java.io.File;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
import java.util.HashMap;
-import java.util.ArrayList;
/**
* UsbAlsaManager manages USB audio and MIDI devices.
@@ -219,23 +216,23 @@
AlsaDevice testDevice = new AlsaDevice(type, card, device);
// This value was empirically determined.
- final int kWaitTime = 2500; // ms
+ final int kWaitTimeMs = 2500;
synchronized(mAlsaDevices) {
- long timeout = SystemClock.elapsedRealtime() + kWaitTime;
+ long timeoutMs = SystemClock.elapsedRealtime() + kWaitTimeMs;
do {
if (mAlsaDevices.values().contains(testDevice)) {
return testDevice;
}
- long waitTime = timeout - SystemClock.elapsedRealtime();
- if (waitTime > 0) {
+ long waitTimeMs = timeoutMs - SystemClock.elapsedRealtime();
+ if (waitTimeMs > 0) {
try {
- mAlsaDevices.wait(waitTime);
+ mAlsaDevices.wait(waitTimeMs);
} catch (InterruptedException e) {
Slog.d(TAG, "usb: InterruptedException while waiting for ALSA file.");
}
}
- } while (timeout > SystemClock.elapsedRealtime());
+ } while (timeoutMs > SystemClock.elapsedRealtime());
}
Slog.e(TAG, "waitForAlsaDevice failed for " + testDevice);
@@ -498,6 +495,7 @@
// Devices List
//
/*
+ //import java.util.ArrayList;
public ArrayList<UsbAudioDevice> getConnectedDevices() {
ArrayList<UsbAudioDevice> devices = new ArrayList<UsbAudioDevice>(mAudioDevices.size());
for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) {
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 808b5d3..a7bdabd 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -138,7 +138,7 @@
mSaturation = saturation;
final ColorMatrixColorFilter filter =
(ColorMatrixColorFilter) mColorMatrixPaint.getColorFilter();
- final ColorMatrix m = filter.getColorMatrix();
+ final ColorMatrix m = new ColorMatrix();
m.setSaturation(saturation);
filter.setColorMatrix(m);
invalidate();
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 79f6e4d..504d54e 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -24,6 +24,7 @@
android.test.runner
LOCAL_PACKAGE_NAME := FrameworksNetTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index ff5a5e9..aaff5d5 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -16,7 +16,6 @@
package android.graphics;
-import android.text.FontConfig;
import com.android.ide.common.rendering.api.AssetRepository;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
@@ -293,12 +292,16 @@
@LayoutlibDelegate
/*package*/ static boolean nAddFontWeightStyle(long builderPtr, ByteBuffer font,
- int ttcIndex, List<FontConfig.Axis> listOfAxis,
- int weight, boolean isItalic) {
+ int ttcIndex, int weight, boolean isItalic) {
assert false : "The only client of this method has been overriden.";
return false;
}
+ @LayoutlibDelegate
+ /*package*/ static void nAddAxisValue(long builderPtr, int tag, float value) {
+ assert false : "The only client of this method has been overriden.";
+ }
+
static boolean addFont(long builderPtr, final String path, final int weight,
final boolean isItalic) {
final FontFamily_Delegate delegate = getDelegate(builderPtr);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index aa1f00d..1bb56e3 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -964,8 +964,9 @@
}
@LayoutlibDelegate
- /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, char[] text,
- int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
+ /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, long typefacePtr,
+ char[] text, int contextStart, int contextLength, int flags, int offset,
+ int cursorOpt) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Paint.getTextRunCursor is not supported.", null, null /*data*/);
@@ -973,8 +974,8 @@
}
@LayoutlibDelegate
- /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, String text,
- int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
+ /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, long typefacePtr,
+ String text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Paint.getTextRunCursor is not supported.", null, null /*data*/);
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a1099f8..04f9059 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -281,7 +281,9 @@
public int apChannel = 0;
/**
- * Pre-shared key for use with WPA-PSK.
+ * Pre-shared key for use with WPA-PSK. Either an ASCII string enclosed in
+ * double quotation marks (e.g., {@code "abcdefghij"} for PSK passphrase or
+ * a string of 64 hex digits for raw PSK.
* <p/>
* When the value of this key is read, the actual key is
* not returned, just a "*" if the key has a value, or the null
@@ -305,7 +307,7 @@
/**
* Priority determines the preference given to a network by {@code wpa_supplicant}
* when choosing an access point with which to associate.
- * @deprecated Priority is no longer used.
+ * @deprecated This field does not exist anymore.
*/
@Deprecated
public int priority;
@@ -434,6 +436,13 @@
public int dtimInterval = 0;
/**
+ * Flag indicating if this configuration represents a legacy Passpoint configuration
+ * (Release N or older). This is used for migrating Passpoint configuration from N to O.
+ * This will no longer be needed after O.
+ * @hide
+ */
+ public boolean isLegacyPasspointConfig = false;
+ /**
* @hide
* Uid of app creating the configuration
*/
@@ -1961,6 +1970,7 @@
mCachedConfigKey = null; //force null configKey
selfAdded = source.selfAdded;
validatedInternetAccess = source.validatedInternetAccess;
+ isLegacyPasspointConfig = source.isLegacyPasspointConfig;
ephemeral = source.ephemeral;
meteredHint = source.meteredHint;
meteredOverride = source.meteredOverride;
@@ -2037,6 +2047,7 @@
dest.writeInt(selfAdded ? 1 : 0);
dest.writeInt(didSelfAdd ? 1 : 0);
dest.writeInt(validatedInternetAccess ? 1 : 0);
+ dest.writeInt(isLegacyPasspointConfig ? 1 : 0);
dest.writeInt(ephemeral ? 1 : 0);
dest.writeInt(meteredHint ? 1 : 0);
dest.writeInt(meteredOverride ? 1 : 0);
@@ -2103,6 +2114,7 @@
config.selfAdded = in.readInt() != 0;
config.didSelfAdd = in.readInt() != 0;
config.validatedInternetAccess = in.readInt() != 0;
+ config.isLegacyPasspointConfig = in.readInt() != 0;
config.ephemeral = in.readInt() != 0;
config.meteredHint = in.readInt() != 0;
config.meteredOverride = in.readInt() != 0;
diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
index eac49d2..8dc244f 100644
--- a/wifi/tests/Android.mk
+++ b/wifi/tests/Android.mk
@@ -58,5 +58,6 @@
android.test.runner \
LOCAL_PACKAGE_NAME := FrameworksWifiApiTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
include $(BUILD_PACKAGE)