Merge "Enable background restrictions"
diff --git a/core/java/android/app/FragmentTransition.java b/core/java/android/app/FragmentTransition.java
index 6d57cd4..80a5aac 100644
--- a/core/java/android/app/FragmentTransition.java
+++ b/core/java/android/app/FragmentTransition.java
@@ -188,7 +188,10 @@
private static void configureTransitionsOptimized(FragmentManagerImpl fragmentManager,
int containerId, FragmentContainerTransition fragments,
View nonExistentView, ArrayMap<String, String> nameOverrides) {
- ViewGroup sceneRoot = (ViewGroup) fragmentManager.mContainer.onFindViewById(containerId);
+ ViewGroup sceneRoot = null;
+ if (fragmentManager.mContainer.onHasView()) {
+ sceneRoot = (ViewGroup) fragmentManager.mContainer.onFindViewById(containerId);
+ }
if (sceneRoot == null) {
return;
}
@@ -257,7 +260,10 @@
private static void configureTransitionsUnoptimized(FragmentManagerImpl fragmentManager,
int containerId, FragmentContainerTransition fragments,
View nonExistentView, ArrayMap<String, String> nameOverrides) {
- ViewGroup sceneRoot = (ViewGroup) fragmentManager.mContainer.onFindViewById(containerId);
+ ViewGroup sceneRoot = null;
+ if (fragmentManager.mContainer.onHasView()) {
+ sceneRoot = (ViewGroup) fragmentManager.mContainer.onFindViewById(containerId);
+ }
if (sceneRoot == null) {
return;
}
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index c704ef0..0775bda 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -24,8 +24,10 @@
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
+import android.service.NetworkIdentityProto;
import android.telephony.TelephonyManager;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
import java.util.Objects;
@@ -110,6 +112,23 @@
return builder.append("}").toString();
}
+ public void writeToProto(ProtoOutputStream proto, long tag) {
+ final long start = proto.start(tag);
+
+ proto.write(NetworkIdentityProto.TYPE, mType);
+
+ // Not dumping mSubType, subtypes are no longer supported.
+
+ if (mSubscriberId != null) {
+ proto.write(NetworkIdentityProto.SUBSCRIBER_ID, scrubSubscriberId(mSubscriberId));
+ }
+ proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId);
+ proto.write(NetworkIdentityProto.ROAMING, mRoaming);
+ proto.write(NetworkIdentityProto.METERED, mMetered);
+
+ proto.end(start);
+ }
+
public int getType() {
return mType;
}
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 4a4accb..5f521de 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -31,7 +31,10 @@
import android.os.Parcel;
import android.os.Parcelable;
+import android.service.NetworkStatsHistoryBucketProto;
+import android.service.NetworkStatsHistoryProto;
import android.util.MathUtils;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.util.IndentingPrintWriter;
@@ -628,6 +631,33 @@
}
}
+ public void writeToProto(ProtoOutputStream proto, long tag) {
+ final long start = proto.start(tag);
+
+ proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration);
+
+ for (int i = 0; i < bucketCount; i++) {
+ final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS);
+
+ proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]);
+ writeToProto(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
+ writeToProto(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
+ writeToProto(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
+ writeToProto(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
+ writeToProto(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
+
+ proto.end(startBucket);
+ }
+
+ proto.end(start);
+ }
+
+ private static void writeToProto(ProtoOutputStream proto, long tag, long[] array, int index) {
+ if (array != null) {
+ proto.write(tag, array[index]);
+ }
+ }
+
@Override
public String toString() {
final CharArrayWriter writer = new CharArrayWriter();
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1b42a90..a479bb3 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1788,15 +1788,15 @@
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
- final PointF point = getLocalPoint();
- if (isTransformedTouchPointInView(x, y, child, point)) {
- final PointerIcon pointerIcon =
- dispatchResolvePointerIcon(event, pointerIndex, child);
- if (pointerIcon != null) {
- if (preorderedList != null) preorderedList.clear();
- return pointerIcon;
- }
- break;
+ if (!canViewReceivePointerEvents(child)
+ || !isTransformedTouchPointInView(x, y, child, null)) {
+ continue;
+ }
+ final PointerIcon pointerIcon =
+ dispatchResolvePointerIcon(event, pointerIndex, child);
+ if (pointerIcon != null) {
+ if (preorderedList != null) preorderedList.clear();
+ return pointerIcon;
}
}
if (preorderedList != null) preorderedList.clear();
@@ -2091,11 +2091,12 @@
getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
final View child =
getAndVerifyPreorderedView(preorderedList, children, childIndex);
- final PointF point = getLocalPoint();
- if (isTransformedTouchPointInView(x, y, child, point)) {
- if (dispatchTooltipHoverEvent(event, child)) {
- newTarget = child;
- }
+ if (!canViewReceivePointerEvents(child)
+ || !isTransformedTouchPointInView(x, y, child, null)) {
+ continue;
+ }
+ if (dispatchTooltipHoverEvent(event, child)) {
+ newTarget = child;
break;
}
}
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index 6b634df..4150636 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -78,6 +78,9 @@
status_t android_view_PointerIcon_getLoadedIcon(JNIEnv* env, jobject pointerIconObj,
PointerIcon* outPointerIcon) {
+ if (!pointerIconObj) {
+ return BAD_VALUE;
+ }
outPointerIcon->style = env->GetIntField(pointerIconObj, gPointerIconClassInfo.mType);
outPointerIcon->hotSpotX = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotX);
outPointerIcon->hotSpotY = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotY);
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index ec2f32b..c3b0ff1 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -21,6 +21,7 @@
import "frameworks/base/libs/incident/proto/android/privacy.proto";
import "frameworks/base/core/proto/android/service/fingerprint.proto";
+import "frameworks/base/core/proto/android/service/netstats.proto";
package android.os;
@@ -49,4 +50,5 @@
// System Services
android.service.fingerprint.FingerprintServiceDumpProto fingerprint = 3000;
+ android.service.NetworkStatsServiceDumpProto netstats = 3001;
}
diff --git a/core/proto/android/service/netstats.proto b/core/proto/android/service/netstats.proto
new file mode 100644
index 0000000..5cca6ab
--- /dev/null
+++ b/core/proto/android/service/netstats.proto
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package android.service;
+
+option java_multiple_files = true;
+option java_outer_classname = "NetworkStatsServiceProto";
+
+// Represents dumpsys from NetworkStatsService (netstats).
+message NetworkStatsServiceDumpProto {
+ repeated NetworkInterfaceProto active_interfaces = 1;
+
+ repeated NetworkInterfaceProto active_uid_interfaces = 2;
+
+ NetworkStatsRecorderProto dev_stats = 3;
+
+ NetworkStatsRecorderProto xt_stats = 4;
+
+ NetworkStatsRecorderProto uid_stats = 5;
+
+ NetworkStatsRecorderProto uid_tag_stats = 6;
+}
+
+// Corresponds to NetworkStatsService.mActiveIfaces/mActiveUidIfaces.
+message NetworkInterfaceProto {
+ string interface = 1;
+
+ NetworkIdentitySetProto identities = 2;
+}
+
+// Corresponds to NetworkIdentitySet.
+message NetworkIdentitySetProto {
+ repeated NetworkIdentityProto identities = 1;
+}
+
+// Corresponds to NetworkIdentity.
+message NetworkIdentityProto {
+ // Constats from ConnectivityManager.TYPE_*.
+ int32 type = 1;
+
+ string subscriber_id = 2;
+
+ string network_id = 3;
+
+ bool roaming = 4;
+
+ bool metered = 5;
+}
+
+// Corresponds to NetworkStatsRecorder.
+message NetworkStatsRecorderProto {
+ int64 pending_total_bytes = 1;
+
+ NetworkStatsCollectionProto complete_history = 2;
+}
+
+// Corresponds to NetworkStatsCollection.
+message NetworkStatsCollectionProto {
+ repeated NetworkStatsCollectionStatsProto stats = 1;
+}
+
+// Corresponds to NetworkStatsCollection.mStats.
+message NetworkStatsCollectionStatsProto {
+ NetworkStatsCollectionKeyProto key = 1;
+
+ NetworkStatsHistoryProto history = 2;
+}
+
+// Corresponds to NetworkStatsCollection.Key.
+message NetworkStatsCollectionKeyProto {
+ NetworkIdentitySetProto identity = 1;
+
+ int32 uid = 2;
+
+ int32 set = 3;
+
+ int32 tag = 4;
+}
+
+// Corresponds to NetworkStatsHistory.
+message NetworkStatsHistoryProto {
+ // Duration for this bucket in milliseconds.
+ int64 bucket_duration_ms = 1;
+
+ repeated NetworkStatsHistoryBucketProto buckets = 2;
+}
+
+// Corresponds to each bucket in NetworkStatsHistory.
+message NetworkStatsHistoryBucketProto {
+ // Bucket start time in milliseconds since epoch.
+ int64 bucket_start_ms = 1;
+
+ int64 rx_bytes = 2;
+
+ int64 rx_packets = 3;
+
+ int64 tx_bytes = 4;
+
+ int64 tx_packets = 5;
+
+ int64 operations = 6;
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index e1657c7..f8f4f2a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -29,6 +29,7 @@
import android.util.Slog;
import android.util.TypedValue;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.GridLayout;
import android.widget.TextClock;
import android.widget.TextView;
@@ -48,6 +49,7 @@
private TextClock mDateView;
private TextClock mClockView;
private TextView mOwnerInfo;
+ private ViewGroup mClockContainer;
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@@ -105,6 +107,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mClockContainer = (ViewGroup) findViewById(R.id.keyguard_clock_container);
mAlarmStatusView = (TextView) findViewById(R.id.alarm_status);
mDateView = (TextClock) findViewById(R.id.date_view);
mClockView = (TextClock) findViewById(R.id.clock_view);
@@ -167,6 +170,11 @@
}
}
+ public int getClockBottom() {
+ return mClockView.getBottom() +
+ ((MarginLayoutParams) mClockView.getLayoutParams()).bottomMargin;
+ }
+
public static String formatNextAlarm(Context context, AlarmManager.AlarmClockInfo info) {
if (info == null) {
return "";
@@ -260,4 +268,15 @@
cacheKey = key;
}
}
+
+ public void setDark(boolean dark) {
+ final int N = mClockContainer.getChildCount();
+ for (int i = 0; i < N; i++) {
+ View child = mClockContainer.getChildAt(i);
+ if (child == mClockView) {
+ continue;
+ }
+ child.setAlpha(dark ? 0 : 1);
+ }
+ }
}
diff --git a/packages/SystemUI/res/drawable/ic_qs_nfc_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_nfc_disabled.xml
new file mode 100644
index 0000000..558f3d0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_nfc_disabled.xml
@@ -0,0 +1,31 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:pathData="M4 20h16V4H4v16z" />
+ <path
+ android:fillColor="#4DFFFFFF"
+ android:pathData="M20 2H4c-1.1 0-2 .9-2 2v16c0 1.1 .9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0
+18H4V4h16v16zM18 6h-5c-1.1 0-2 .9-2 2v2.28c-.6 .35 -1 .98-1 1.72 0 1.1 .9 2 2
+2s2-.9 2-2c0-.74-.4-1.38-1-1.72V8h3v8H8V8h2V6H6v12h12V6z" />
+ <path
+ android:pathData="M0 0h24v24H0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_nfc_enabled.xml b/packages/SystemUI/res/drawable/ic_qs_nfc_enabled.xml
new file mode 100644
index 0000000..becb18a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_nfc_enabled.xml
@@ -0,0 +1,31 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:pathData="M4 20h16V4H4v16z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M20 2H4c-1.1 0-2 .9-2 2v16c0 1.1 .9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0
+18H4V4h16v16zM18 6h-5c-1.1 0-2 .9-2 2v2.28c-.6 .35 -1 .98-1 1.72 0 1.1 .9 2 2
+2s2-.9 2-2c0-.74-.4-1.38-1-1.72V8h3v8H8V8h2V6H6v12h12V6z" />
+ <path
+ android:pathData="M0 0h24v24H0z" />
+</vector>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 78d211f..6ffdbcb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -75,6 +75,9 @@
<!-- Height of a large notification in the status bar -->
<dimen name="notification_max_height">284dp</dimen>
+ <!-- Height of an ambient notification on ambient display -->
+ <dimen name="notification_ambient_height">400dp</dimen>
+
<!-- Height of a heads up notification in the status bar for legacy custom views -->
<dimen name="notification_max_heads_up_height_legacy">128dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 69515fa..a17430a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -760,6 +760,12 @@
<string name="quick_settings_work_mode_label">Work mode</string>
<!-- QuickSettings: Label for the toggle to activate Night display (renamed "Night Light" with title caps). [CHAR LIMIT=20] -->
<string name="quick_settings_night_display_label">Night Light</string>
+ <!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_nfc_label">NFC</string>
+ <!-- QuickSettings: NFC (off) [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_nfc_off">NFC is disabled</string>
+ <!-- QuickSettings: NFC (on) [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_nfc_on">NFC is enabled</string>
<!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
<string name="recents_empty_message">No recent items</string>
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index e081b53..00d2298 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -37,7 +37,7 @@
interface Callback {
default void onNewNotifications() {}
- default void onBuzzBeepBlinked() {}
+ default void onNotificationHeadsUp() {}
default void onNotificationLight(boolean on) {}
default void onPowerSaveChanged(boolean active) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 84b22ea..db5a392 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -309,7 +309,7 @@
private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
@Override
- public void onBuzzBeepBlinked() {
+ public void onNotificationHeadsUp() {
onNotification();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
new file mode 100644
index 0000000..967c922
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016, The Android Open Source Project
+ * Contributed by the Paranoid Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.nfc.NfcAdapter;
+import android.provider.Settings;
+import android.widget.Switch;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+
+/** Quick settings tile: Enable/Disable NFC **/
+public class NfcTile extends QSTile<QSTile.BooleanState> {
+
+ private NfcAdapter mAdapter;
+
+ private boolean mListening;
+
+ public NfcTile(Host host) {
+ super(host);
+ }
+
+ @Override
+ public BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ mListening = listening;
+ if (mListening) {
+ mContext.registerReceiver(mNfcReceiver,
+ new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED));
+ if (mAdapter == null) {
+ try {
+ mAdapter = NfcAdapter.getNfcAdapter(mContext);
+ } catch (UnsupportedOperationException e) {
+ mAdapter = null;
+ }
+ }
+ } else {
+ mContext.unregisterReceiver(mNfcReceiver);
+ }
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC);
+ }
+
+ @Override
+ protected void handleUserSwitch(int newUserId) {
+ }
+
+ @Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_NFC_SETTINGS);
+ }
+
+ @Override
+ protected void handleClick() {
+ if (mAdapter == null) return;
+ MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
+ if (!mAdapter.isEnabled()) {
+ mAdapter.enable();
+ } else {
+ mAdapter.disable();
+ }
+ }
+
+ @Override
+ protected void handleSecondaryClick() {
+ handleClick();
+ }
+
+ @Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_nfc_label);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ final Drawable mEnable = mContext.getDrawable(R.drawable.ic_qs_nfc_enabled);
+ final Drawable mDisable = mContext.getDrawable(R.drawable.ic_qs_nfc_disabled);
+ state.value = mAdapter == null ? false : mAdapter.isEnabled();
+ state.label = mContext.getString(R.string.quick_settings_nfc_label);
+ state.icon = new DrawableIcon(state.value ? mEnable : mDisable);
+ state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+ = Switch.class.getName();
+ state.contentDescription = state.label;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.QS_NFC;
+ }
+
+ @Override
+ protected String composeChangeAnnouncement() {
+ if (mState.value) {
+ return mContext.getString(R.string.quick_settings_nfc_on);
+ } else {
+ return mContext.getString(R.string.quick_settings_nfc_off);
+ }
+ }
+
+ private BroadcastReceiver mNfcReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ refreshState();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index e39c64e..faf143e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1524,6 +1524,7 @@
final RemoteViews bigContentView = entry.cachedBigContentView;
final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
final RemoteViews publicContentView = entry.cachedPublicContentView;
+ final RemoteViews ambientContentView = entry.cachedAmbientContentView;
if (contentView == null) {
Log.v(TAG, "no contentView for: " + sbn.getNotification());
@@ -1604,6 +1605,7 @@
View bigContentViewLocal = null;
View headsUpContentViewLocal = null;
View publicViewLocal = null;
+ View ambientViewLocal = null;
try {
contentViewLocal = contentView.apply(
sbn.getPackageContext(mContext),
@@ -1626,6 +1628,11 @@
sbn.getPackageContext(mContext),
contentContainerPublic, mOnClickHandler);
}
+ if (ambientContentView != null) {
+ ambientViewLocal = ambientContentView.apply(
+ sbn.getPackageContext(mContext),
+ contentContainer, mOnClickHandler);
+ }
if (contentViewLocal != null) {
contentViewLocal.setIsRootNamespace(true);
@@ -1643,6 +1650,11 @@
publicViewLocal.setIsRootNamespace(true);
contentContainerPublic.setContractedChild(publicViewLocal);
}
+
+ if (ambientViewLocal != null) {
+ ambientViewLocal.setIsRootNamespace(true);
+ contentContainer.setAmbientChild(ambientViewLocal);
+ }
}
catch (RuntimeException e) {
final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
@@ -2139,6 +2151,7 @@
row.setOnKeyguard(false);
row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
}
+ entry.row.setShowAmbient(isDozing());
int userId = entry.notification.getUserId();
boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
entry.notification) && !entry.row.isRemoved();
@@ -2176,6 +2189,10 @@
mStackScroller.changeViewPosition(mNotificationShelf, mStackScroller.getChildCount() - 3);
}
+ public boolean isDozing() {
+ return false;
+ }
+
public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
}
@@ -2388,7 +2405,7 @@
Log.d(TAG, "failed to query dream manager", e);
}
- if (!inUse) {
+ if (!inUse && !isDozing()) {
if (DEBUG) {
Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 173a110..93c48f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -74,6 +74,7 @@
private int mMaxHeadsUpHeight;
private int mNotificationMinHeight;
private int mNotificationMaxHeight;
+ private int mNotificationAmbientHeight;
private int mIncreasedPaddingBetweenElements;
/** Does this row contain layouts that can adapt to row expansion */
@@ -197,6 +198,7 @@
private float mContentTransformationAmount;
private boolean mIconsVisible = true;
private boolean mAboveShelf;
+ private boolean mShowAmbient;
private boolean mIsLastChild;
private Runnable mOnDismissRunnable;
@@ -326,7 +328,8 @@
!= com.android.internal.R.id.status_bar_latest_event_content;
int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
: mMaxHeadsUpHeight;
- layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
+ layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
+ mNotificationAmbientHeight);
}
public StatusBarNotification getStatusBarNotification() {
@@ -954,6 +957,7 @@
mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
+ mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
mMaxHeadsUpHeightLegacy = getFontScaledHeight(
R.dimen.notification_max_heads_up_height_legacy);
mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
@@ -1353,6 +1357,8 @@
return mGuts.getHeight();
} else if ((isChildInGroup() && !isGroupExpanded())) {
return mPrivateLayout.getMinHeight();
+ } else if (mShowAmbient) {
+ return getAmbientHeight();
} else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
return getMinHeight();
} else if (mIsSummaryWithChildren && !mOnKeyguard) {
@@ -1683,6 +1689,13 @@
return showingLayout.getMinHeight();
}
+ private int getAmbientHeight() {
+ NotificationContentView showingLayout = getShowingLayout();
+ return showingLayout.getAmbientChild() != null
+ ? showingLayout.getAmbientChild().getHeight()
+ : getCollapsedHeight();
+ }
+
@Override
public int getCollapsedHeight() {
if (mIsSummaryWithChildren && !mShowingPublic) {
@@ -1879,6 +1892,13 @@
return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
}
+ public void setShowAmbient(boolean showAmbient) {
+ if (showAmbient != mShowAmbient) {
+ mShowAmbient = showAmbient;
+ notifyHeightChanged(false /* needsAnimation */);
+ }
+ }
+
public void setAboveShelf(boolean aboveShelf) {
mAboveShelf = aboveShelf;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 9ce2115..077303a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -52,6 +52,7 @@
private static final int VISIBLE_TYPE_EXPANDED = 1;
private static final int VISIBLE_TYPE_HEADSUP = 2;
private static final int VISIBLE_TYPE_SINGLELINE = 3;
+ private static final int VISIBLE_TYPE_AMBIENT = 4;
public static final int UNDEFINED = -1;
private final Rect mClipBounds = new Rect();
@@ -62,6 +63,7 @@
private View mExpandedChild;
private View mHeadsUpChild;
private HybridNotificationView mSingleLineView;
+ private View mAmbientChild;
private RemoteInputView mExpandedRemoteInput;
private RemoteInputView mHeadsUpRemoteInput;
@@ -69,6 +71,7 @@
private NotificationViewWrapper mContractedWrapper;
private NotificationViewWrapper mExpandedWrapper;
private NotificationViewWrapper mHeadsUpWrapper;
+ private NotificationViewWrapper mAmbientWrapper;
private HybridGroupManager mHybridGroupManager;
private int mClipTopAmount;
private int mContentHeight;
@@ -81,6 +84,7 @@
private int mSmallHeight;
private int mHeadsUpHeight;
private int mNotificationMaxHeight;
+ private int mNotificationAmbientHeight;
private StatusBarNotification mStatusBarNotification;
private NotificationGroupManager mGroupManager;
private RemoteInputController mRemoteInputController;
@@ -136,10 +140,12 @@
reset();
}
- public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
+ public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight,
+ int ambientHeight) {
mSmallHeight = smallHeight;
mHeadsUpHeight = headsUpMaxHeight;
mNotificationMaxHeight = maxHeight;
+ mNotificationAmbientHeight = ambientHeight;
}
@Override
@@ -215,6 +221,17 @@
MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST));
maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
}
+ if (mAmbientChild != null) {
+ int size = Math.min(maxSize, mNotificationAmbientHeight);
+ ViewGroup.LayoutParams layoutParams = mAmbientChild.getLayoutParams();
+ if (layoutParams.height >= 0) {
+ // An actual height is set
+ size = Math.min(size, layoutParams.height);
+ }
+ mAmbientChild.measure(widthMeasureSpec,
+ MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
+ maxChildHeight = Math.max(maxChildHeight, mAmbientChild.getMeasuredHeight());
+ }
int ownHeight = Math.min(maxChildHeight, maxSize);
setMeasuredDimension(width, ownHeight);
}
@@ -339,6 +356,10 @@
return mHeadsUpChild;
}
+ public View getAmbientChild() {
+ return mAmbientChild;
+ }
+
public void setContractedChild(View child) {
if (mContractedChild != null) {
mContractedChild.animate().cancel();
@@ -373,6 +394,17 @@
mContainingNotification);
}
+ public void setAmbientChild(View child) {
+ if (mAmbientChild != null) {
+ mAmbientChild.animate().cancel();
+ removeView(mAmbientChild);
+ }
+ addView(child);
+ mAmbientChild = child;
+ mAmbientWrapper = NotificationViewWrapper.wrap(getContext(), child,
+ mContainingNotification);
+ }
+
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
@@ -447,6 +479,11 @@
com.android.internal.R.dimen.notification_action_list_height);
}
+ if (isVisibleOrTransitioning(VISIBLE_TYPE_AMBIENT)) {
+ return mContractedChild.getHeight() + mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_action_list_height);
+ }
+
// Transition between heads-up & expanded, or pinned.
if (mHeadsUpChild != null && mExpandedChild != null) {
boolean transitioningBetweenHunAndExpanded =
@@ -651,39 +688,23 @@
}
private void forceUpdateVisibilities() {
- boolean contractedVisible = mVisibleType == VISIBLE_TYPE_CONTRACTED
- || mTransformationStartVisibleType == VISIBLE_TYPE_CONTRACTED;
- boolean expandedVisible = mVisibleType == VISIBLE_TYPE_EXPANDED
- || mTransformationStartVisibleType == VISIBLE_TYPE_EXPANDED;
- boolean headsUpVisible = mVisibleType == VISIBLE_TYPE_HEADSUP
- || mTransformationStartVisibleType == VISIBLE_TYPE_HEADSUP;
- boolean singleLineVisible = mVisibleType == VISIBLE_TYPE_SINGLELINE
- || mTransformationStartVisibleType == VISIBLE_TYPE_SINGLELINE;
- if (!contractedVisible) {
- mContractedChild.setVisibility(View.INVISIBLE);
+ forceUpdateVisibility(VISIBLE_TYPE_CONTRACTED, mContractedChild, mContractedWrapper);
+ forceUpdateVisibility(VISIBLE_TYPE_EXPANDED, mExpandedChild, mExpandedWrapper);
+ forceUpdateVisibility(VISIBLE_TYPE_HEADSUP, mHeadsUpChild, mHeadsUpWrapper);
+ forceUpdateVisibility(VISIBLE_TYPE_SINGLELINE, mSingleLineView, mSingleLineView);
+ forceUpdateVisibility(VISIBLE_TYPE_AMBIENT, mAmbientChild, mAmbientWrapper);
+ }
+
+ private void forceUpdateVisibility(int type, View view, TransformableView wrapper) {
+ if (view == null) {
+ return;
+ }
+ boolean visible = mVisibleType == type
+ || mTransformationStartVisibleType == type;
+ if (!visible) {
+ view.setVisibility(INVISIBLE);
} else {
- mContractedWrapper.setVisible(true);
- }
- if (mExpandedChild != null) {
- if (!expandedVisible) {
- mExpandedChild.setVisibility(View.INVISIBLE);
- } else {
- mExpandedWrapper.setVisible(true);
- }
- }
- if (mHeadsUpChild != null) {
- if (!headsUpVisible) {
- mHeadsUpChild.setVisibility(View.INVISIBLE);
- } else {
- mHeadsUpWrapper.setVisible(true);
- }
- }
- if (mSingleLineView != null) {
- if (!singleLineVisible) {
- mSingleLineView.setVisibility(View.INVISIBLE);
- } else {
- mSingleLineView.setVisible(true);
- }
+ wrapper.setVisible(true);
}
}
@@ -717,19 +738,22 @@
}
private void updateViewVisibilities(int visibleType) {
- boolean contractedVisible = visibleType == VISIBLE_TYPE_CONTRACTED;
- mContractedWrapper.setVisible(contractedVisible);
- if (mExpandedChild != null) {
- boolean expandedVisible = visibleType == VISIBLE_TYPE_EXPANDED;
- mExpandedWrapper.setVisible(expandedVisible);
- }
- if (mHeadsUpChild != null) {
- boolean headsUpVisible = visibleType == VISIBLE_TYPE_HEADSUP;
- mHeadsUpWrapper.setVisible(headsUpVisible);
- }
- if (mSingleLineView != null) {
- boolean singleLineVisible = visibleType == VISIBLE_TYPE_SINGLELINE;
- mSingleLineView.setVisible(singleLineVisible);
+ updateViewVisibility(visibleType, VISIBLE_TYPE_CONTRACTED,
+ mContractedChild, mContractedWrapper);
+ updateViewVisibility(visibleType, VISIBLE_TYPE_EXPANDED,
+ mExpandedChild, mExpandedWrapper);
+ updateViewVisibility(visibleType, VISIBLE_TYPE_HEADSUP,
+ mHeadsUpChild, mHeadsUpWrapper);
+ updateViewVisibility(visibleType, VISIBLE_TYPE_SINGLELINE,
+ mSingleLineView, mSingleLineView);
+ updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT,
+ mAmbientChild, mAmbientWrapper);
+ }
+
+ private void updateViewVisibility(int visibleType, int type, View view,
+ TransformableView wrapper) {
+ if (view != null) {
+ wrapper.setVisible(visibleType == type);
}
}
@@ -779,6 +803,8 @@
return mHeadsUpWrapper;
case VISIBLE_TYPE_SINGLELINE:
return mSingleLineView;
+ case VISIBLE_TYPE_AMBIENT:
+ return mAmbientWrapper;
default:
return mContractedWrapper;
}
@@ -796,6 +822,8 @@
return mHeadsUpChild;
case VISIBLE_TYPE_SINGLELINE:
return mSingleLineView;
+ case VISIBLE_TYPE_AMBIENT:
+ return mAmbientChild;
default:
return mContractedChild;
}
@@ -809,6 +837,8 @@
return mHeadsUpWrapper;
case VISIBLE_TYPE_CONTRACTED:
return mContractedWrapper;
+ case VISIBLE_TYPE_AMBIENT:
+ return mAmbientWrapper;
default:
return null;
}
@@ -818,6 +848,10 @@
* @return one of the static enum types in this view, calculated form the current state
*/
public int calculateVisibleType() {
+ if (mDark && !mIsChildInGroup) {
+ // TODO: Handle notification groups
+ return VISIBLE_TYPE_AMBIENT;
+ }
if (mUserExpanding) {
int height = !mIsChildInGroup || isGroupExpanded()
|| mContainingNotification.isExpanded(true /* allowOnKeyguard */)
@@ -890,6 +924,7 @@
if (mSingleLineView != null && (mVisibleType == VISIBLE_TYPE_SINGLELINE || !dark)) {
mSingleLineView.setDark(dark, fade, delay);
}
+ selectLayout(!dark && fade /* animate */, false /* force */);
}
public void setHeadsUp(boolean headsUp) {
@@ -942,6 +977,9 @@
if (mHeadsUpChild != null) {
mHeadsUpWrapper.notifyContentUpdated(entry.notification);
}
+ if (mAmbientChild != null) {
+ mAmbientWrapper.notifyContentUpdated(entry.notification);
+ }
updateShowingLegacyBackground();
mForceSelectNextLayout = true;
setDark(mDark, false /* animate */, 0 /* delay */);
@@ -1128,6 +1166,9 @@
if (header == null && mHeadsUpChild != null) {
header = mHeadsUpWrapper.getNotificationHeader();
}
+ if (header == null && mAmbientChild != null) {
+ header = mAmbientWrapper.getNotificationHeader();
+ }
return header;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index c06e639..458daf1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -67,6 +67,7 @@
public RemoteViews cachedBigContentView;
public RemoteViews cachedHeadsUpContentView;
public RemoteViews cachedPublicContentView;
+ public RemoteViews cachedAmbientContentView;
public CharSequence remoteInputText;
private int mCachedContrastColor = COLOR_INVALID;
private int mCachedContrastColorIsFor = COLOR_INVALID;
@@ -126,6 +127,8 @@
updatedNotificationBuilder.createHeadsUpContentView();
final RemoteViews newPublicNotification
= updatedNotificationBuilder.makePublicContentView();
+ final RemoteViews newAmbientNotification
+ = updatedNotificationBuilder.makeAmbientNotification();
boolean sameCustomView = Objects.equals(
notification.getNotification().extras.getBoolean(
@@ -136,11 +139,13 @@
&& compareRemoteViews(cachedBigContentView, newBigContentView)
&& compareRemoteViews(cachedHeadsUpContentView, newHeadsUpContentView)
&& compareRemoteViews(cachedPublicContentView, newPublicNotification)
+ && compareRemoteViews(cachedAmbientContentView, newAmbientNotification)
&& sameCustomView;
cachedPublicContentView = newPublicNotification;
cachedHeadsUpContentView = newHeadsUpContentView;
cachedBigContentView = newBigContentView;
cachedContentView = newContentView;
+ cachedAmbientContentView = newAmbientNotification;
} else {
final Notification.Builder builder
= Notification.Builder.recoverBuilder(ctx, notification.getNotification());
@@ -149,6 +154,7 @@
cachedBigContentView = builder.createBigContentView();
cachedHeadsUpContentView = builder.createHeadsUpContentView();
cachedPublicContentView = builder.makePublicContentView();
+ cachedAmbientContentView = builder.makeAmbientNotification();
applyInPlace = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 64c4949..e8e9d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -129,6 +129,7 @@
} else {
mViewInvertHelper.update(dark);
}
+ mShelfIcons.setAmbient(dark);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 7ca2df9..b984c0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -116,8 +116,10 @@
private void resolveTemplateViews(StatusBarNotification notification) {
mPicture = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
- mPicture.setTag(ImageTransformState.ICON_TAG,
- notification.getNotification().getLargeIcon());
+ if (mPicture != null) {
+ mPicture.setTag(ImageTransformState.ICON_TAG,
+ notification.getNotification().getLargeIcon());
+ }
mTitle = (TextView) mView.findViewById(com.android.internal.R.id.title);
mText = (TextView) mView.findViewById(com.android.internal.R.id.text);
final View progress = mView.findViewById(com.android.internal.R.id.progress);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index 5047041..a4e5916 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -39,6 +39,7 @@
private VisibilityLocationProvider mVisibilityLocationProvider;
private ArraySet<View> mAllowedReorderViews = new ArraySet<>();
private ArraySet<View> mAddedChildren = new ArraySet<>();
+ private boolean mPulsing;
/**
* Add a callback to invoke when reordering is allowed again.
@@ -67,8 +68,16 @@
updateReorderingAllowed();
}
+ /**
+ * @param pulsing whether we are currently pulsing for ambient display.
+ */
+ public void setPulsing(boolean pulsing) {
+ mPulsing = pulsing;
+ updateReorderingAllowed();
+ }
+
private void updateReorderingAllowed() {
- boolean reorderingAllowed = !mScreenOn || !mPanelExpanded;
+ boolean reorderingAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing;
boolean changed = reorderingAllowed && !mReorderingAllowed;
mReorderingAllowed = reorderingAllowed;
if (changed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 01ffe01..b78f748 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -26,6 +26,7 @@
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.Interpolators;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
@@ -41,7 +42,9 @@
private final Handler mHandler = new Handler();
private final ScrimController mScrimController;
+ private final Context mContext;
private final View mStackScroller;
+ private final NotificationPanelView mNotificationPanelView;
private boolean mDozing;
private DozeHost.PulseCallback mPulseCallback;
@@ -52,10 +55,12 @@
private float mBehindTarget;
public DozeScrimController(ScrimController scrimController, Context context,
- View stackScroller) {
+ View stackScroller, NotificationPanelView notificationPanelView) {
+ mContext = context;
mStackScroller = stackScroller;
mScrimController = scrimController;
mDozeParameters = new DozeParameters(context);
+ mNotificationPanelView = notificationPanelView;
}
public void setDozing(boolean dozing, boolean animate) {
@@ -65,10 +70,7 @@
abortAnimations();
mScrimController.setDozeBehindAlpha(1f);
mScrimController.setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() ? 0f : 1f);
- if (mDozeParameters.getAlwaysOn()) {
- mStackScroller.setAlpha(0f);
- mHandler.postDelayed(() -> mStackScroller.setAlpha(0f), 30);
- }
+ mNotificationPanelView.setDark(true);
} else {
cancelPulsing();
if (animate) {
@@ -83,9 +85,8 @@
mScrimController.setDozeBehindAlpha(0f);
mScrimController.setDozeInFrontAlpha(0f);
}
- if (mDozeParameters.getAlwaysOn()) {
- mStackScroller.setAlpha(1f);
- }
+ // TODO: animate
+ mNotificationPanelView.setDark(false);
}
}
@@ -123,9 +124,6 @@
if (isPulsing()) {
final boolean pickupOrDoubleTap = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP
|| mPulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
- if (mDozeParameters.getAlwaysOn()) {
- mStackScroller.setAlpha(1f);
- }
startScrimAnimation(true /* inFront */, 0f,
mDozeParameters.getPulseInDuration(pickupOrDoubleTap),
pickupOrDoubleTap ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
@@ -291,9 +289,6 @@
@Override
public void run() {
if (DEBUG) Log.d(TAG, "Pulse out finished");
- if (mDozeParameters.getAlwaysOn()) {
- mStackScroller.setAlpha(0f);
- }
DozeLog.tracePulseFinish();
// Signal that the pulse is all finished so we can turn the screen off now.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 70beac8ea..c78ec83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -68,6 +68,8 @@
}
private AccelerateInterpolator mAccelerateInterpolator = new AccelerateInterpolator();
+ private int mClockBottom;
+ private boolean mDark;
/**
* Refreshes the dimension values.
@@ -86,7 +88,8 @@
}
public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight,
- int notificationCount, int height, int keyguardStatusHeight, float emptyDragAmount) {
+ int notificationCount, int height, int keyguardStatusHeight, float emptyDragAmount,
+ int clockBottom, boolean dark) {
mMaxKeyguardNotifications = maxKeyguardNotifications;
mMaxPanelHeight = maxPanelHeight;
mExpandedHeight = expandedHeight;
@@ -94,6 +97,8 @@
mHeight = height;
mKeyguardStatusHeight = keyguardStatusHeight;
mEmptyDragAmount = emptyDragAmount;
+ mClockBottom = clockBottom;
+ mDark = dark;
}
public float getMinStackScrollerPadding(int height, int keyguardStatusHeight) {
@@ -115,6 +120,9 @@
result.clockY,
y + getClockNotificationsPadding() + mKeyguardStatusHeight);
result.clockAlpha = getClockAlpha(result.clockScale);
+ if (mDark) {
+ result.stackScrollerPadding = mClockBottom + y;
+ }
}
private float getClockScale(int notificationPadding, int clockY, int startPadding) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 9fb5980..c25a45c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -22,9 +22,7 @@
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
-import android.util.Property;
import android.view.View;
-import android.view.animation.Interpolator;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -32,7 +30,6 @@
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.stack.AnimationFilter;
import com.android.systemui.statusbar.stack.AnimationProperties;
-import com.android.systemui.statusbar.stack.HeadsUpAppearInterpolator;
import com.android.systemui.statusbar.stack.ViewState;
import java.util.HashMap;
@@ -98,6 +95,7 @@
private int mActualLayoutWidth = NO_VALUE;
private float mActualPaddingEnd = NO_VALUE;
private float mActualPaddingStart = NO_VALUE;
+ private boolean mCentered;
private boolean mChangingViewPositions;
private int mAddAnimationStartIndex = -1;
private int mCannedAnimationStartIndex = -1;
@@ -105,6 +103,7 @@
private int mIconSize;
private float mOpenedAmount = 0.0f;
private float mVisualOverflowAdaption;
+ private boolean mDisallowNextAnimation;
public NotificationIconContainer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -165,6 +164,7 @@
}
mAddAnimationStartIndex = -1;
mCannedAnimationStartIndex = -1;
+ mDisallowNextAnimation = false;
}
@Override
@@ -310,6 +310,15 @@
numDots++;
}
}
+ if (mCentered && translationX < getLayoutEnd()) {
+ float delta = (getLayoutEnd() - translationX) / 2;
+ for (int i = 0; i < childCount; i++) {
+ View view = getChildAt(i);
+ IconState iconState = mIconStates.get(view);
+ iconState.xTranslation += delta;
+ }
+ }
+
if (isLayoutRtl()) {
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
@@ -379,6 +388,11 @@
mChangingViewPositions = changingViewPositions;
}
+ public void setAmbient(boolean ambient) {
+ mCentered = ambient;
+ mDisallowNextAnimation = true;
+ }
+
public IconState getIconState(StatusBarIconView icon) {
return mIconStates.get(icon);
}
@@ -469,7 +483,7 @@
animate = true;
}
icon.setVisibleState(visibleState);
- if (animate) {
+ if (animate && !mDisallowNextAnimation) {
animateTo(icon, animationProperties);
} else {
super.applyToView(view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index d48819a..3bdd5e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -211,6 +211,7 @@
private boolean mOpening;
private int mIndicationBottomPadding;
private boolean mIsFullWidth;
+ private boolean mDark;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -391,7 +392,9 @@
mNotificationStackScroller.getNotGoneChildCount(),
getHeight(),
mKeyguardStatusView.getHeight(),
- mEmptyDragAmount);
+ mEmptyDragAmount,
+ mKeyguardStatusView.getClockBottom(),
+ mDark);
mClockPositionAlgorithm.run(mClockPositionResult);
if (animate || mClockAnimator != null) {
startClockAnimation(mClockPositionResult.clockY);
@@ -2453,4 +2456,10 @@
}
}
};
+
+ public void setDark(boolean dark) {
+ mDark = dark;
+ mKeyguardStatusView.setDark(dark);
+ positionClockAndNotifications();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 5998ed2..191718e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -74,7 +74,6 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
@@ -879,7 +878,8 @@
mHeadsUpManager.addListener(mScrimController);
mStackScroller.setScrimController(mScrimController);
mStatusBarView.setScrimController(mScrimController);
- mDozeScrimController = new DozeScrimController(mScrimController, context, mStackScroller);
+ mDozeScrimController = new DozeScrimController(mScrimController, context, mStackScroller,
+ mNotificationPanel);
// Other icons
mLocationController = new LocationControllerImpl(mContext,
@@ -2401,6 +2401,7 @@
return getBarState() == StatusBarState.KEYGUARD;
}
+ @Override
public boolean isDozing() {
return mDozing;
}
@@ -2487,6 +2488,9 @@
}
} else {
updateNotificationRanking(null);
+ if (isHeadsUp) {
+ mDozeServiceHost.fireNotificationHeadsUp();
+ }
}
}
@@ -2886,9 +2890,6 @@
@Override // CommandQueue
public void buzzBeepBlinked() {
- if (mDozeServiceHost != null) {
- mDozeServiceHost.fireBuzzBeepBlinked();
- }
}
@Override
@@ -3518,6 +3519,9 @@
if (mSecurityController != null) {
mSecurityController.onUserSwitched(mCurrentUserId);
}
+ if (mNetworkController != null) {
+ mNetworkController.onUserSwitched(mCurrentUserId);
+ }
}
private void resetUserSetupObserver() {
@@ -4234,6 +4238,7 @@
mDozeScrimController.setDozing(mDozing &&
mFingerprintUnlockController.getMode()
!= FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING, animate);
+ updateRowStates();
Trace.endSection();
}
@@ -4904,9 +4909,9 @@
}
}
- public void fireBuzzBeepBlinked() {
+ public void fireNotificationHeadsUp() {
for (Callback callback : mCallbacks) {
- callback.onBuzzBeepBlinked();
+ callback.onNotificationHeadsUp();
}
}
@@ -4950,12 +4955,14 @@
public void onPulseStarted() {
callback.onPulseStarted();
mStackScroller.setPulsing(true);
+ mVisualStabilityManager.setPulsing(true);
}
@Override
public void onPulseFinished() {
callback.onPulseFinished();
mStackScroller.setPulsing(false);
+ mVisualStabilityManager.setPulsing(false);
}
}, reason);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 227ebdf..d4cf533 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -52,6 +52,7 @@
import com.android.systemui.qs.tiles.HotspotTile;
import com.android.systemui.qs.tiles.IntentTile;
import com.android.systemui.qs.tiles.LocationTile;
+import com.android.systemui.qs.tiles.NfcTile;
import com.android.systemui.qs.tiles.NightDisplayTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.qs.tiles.UserTile;
@@ -440,6 +441,7 @@
else if (tileSpec.equals("battery")) return new BatteryTile(this);
else if (tileSpec.equals("saver")) return new DataSaverTile(this);
else if (tileSpec.equals("night")) return new NightDisplayTile(this);
+ else if (tileSpec.equals("nfc")) return new NfcTile(this);
// Intent tiles.
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 9545fd8..395e8f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1883,12 +1883,16 @@
float previousIncreasedAmount = 0.0f;
int numShownItems = 0;
boolean finish = false;
+ int maxDisplayedNotifications = mAmbientState.isDark()
+ ? (mPulsing ? 1 : 0)
+ : mMaxDisplayedNotifications;
+
for (int i = 0; i < getChildCount(); i++) {
ExpandableView expandableView = (ExpandableView) getChildAt(i);
if (expandableView.getVisibility() != View.GONE
&& !expandableView.hasNoContentHeight()) {
- if (mMaxDisplayedNotifications != -1
- && numShownItems >= mMaxDisplayedNotifications) {
+ if (maxDisplayedNotifications != -1
+ && numShownItems >= maxDisplayedNotifications) {
expandableView = mShelf;
finish = true;
}
@@ -3486,6 +3490,8 @@
updateBackground();
setWillNotDraw(false);
}
+ updateContentHeight();
+ notifyHeightChangeListener(mShelf);
}
private void setBackgroundFadeAmount(float fadeAmount) {
@@ -3921,6 +3927,8 @@
public void setPulsing(boolean pulsing) {
mPulsing = pulsing;
updateNotificationAnimationStates();
+ updateContentHeight();
+ notifyHeightChangeListener(mShelf);
}
public void setFadingOut(boolean fadingOut) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java
index be6290b..76bb6c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java
@@ -150,4 +150,28 @@
mVisualStabilityManager.onReorderingFinished();
assertEquals(mVisualStabilityManager.canReorderNotification(mRow), false);
}
+
+ @Test
+ public void testPulsing() {
+ mVisualStabilityManager.setPulsing(true);
+ assertEquals(mVisualStabilityManager.canReorderNotification(mRow), false);
+ mVisualStabilityManager.setPulsing(false);
+ assertEquals(mVisualStabilityManager.canReorderNotification(mRow), true);
+ }
+
+ @Test
+ public void testReorderingAllowedChanges_Pulsing() {
+ mVisualStabilityManager.setPulsing(true);
+ assertEquals(mVisualStabilityManager.isReorderingAllowed(), false);
+ mVisualStabilityManager.setPulsing(false);
+ assertEquals(mVisualStabilityManager.isReorderingAllowed(), true);
+ }
+
+ @Test
+ public void testCallBackCalled_Pulsing() {
+ mVisualStabilityManager.setPulsing(true);
+ mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
+ mVisualStabilityManager.setPulsing(false);
+ verify(mCallback).onReorderingAllowed();
+ }
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index dc92f56..ac0a4a28 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3191,8 +3191,76 @@
// ACTION: Clicking on any search result in Settings.
ACTION_CLICK_SETTINGS_SEARCH_RESULT = 763;
+ // ACTION: Allow Battery optimization for an app
+ APP_SPECIAL_PERMISSION_BATTERY_ALLOW = 764;
+
+ // ACTION: Deny Battery optimization for an app
+ APP_SPECIAL_PERMISSION_BATTERY_DENY = 765;
+
+ // ACTION: Enable Device Admin app
+ APP_SPECIAL_PERMISSION_ADMIN_ALLOW = 766;
+
+ // ACTION: Disable Device Admin app
+ APP_SPECIAL_PERMISSION_ADMIN_DENY = 767;
+
+ // ACTION: Allow "Do Not Disturb access" for an app
+ APP_SPECIAL_PERMISSION_DND_ALLOW = 768;
+
+ // ACTION: Deny "Do Not Disturb access" for an app
+ APP_SPECIAL_PERMISSION_DND_DENY = 769;
+
+ // ACTION: Allow "Draw over other apps" for an app
+ APP_SPECIAL_PERMISSION_APPDRAW_ALLOW = 770;
+
+ // ACTION: Deny "Draw over other apps" for an app
+ APP_SPECIAL_PERMISSION_APPDRAW_DENY = 771;
+
+ // ACTION: Allow "VR helper services" for an app
+ APP_SPECIAL_PERMISSION_VRHELPER_ALLOW = 772;
+
+ // ACTION: Deny "VR helper services" for an app
+ APP_SPECIAL_PERMISSION_VRHELPER_DENY = 773;
+
+ // ACTION: Allow "Modify system settings" for an app
+ APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_ALLOW = 774;
+
+ // ACTION: Deny "Modify system settings" for an app
+ APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_DENY = 775;
+
+ // ACTION: Allow "Notification access" for an app
+ APP_SPECIAL_PERMISSION_NOTIVIEW_ALLOW = 776;
+
+ // ACTION: Deny "Notification access" for an app
+ APP_SPECIAL_PERMISSION_NOTIVIEW_DENY = 777;
+
+ // ACTION: "Premium SMS access" for an app - "ask user" option
+ APP_SPECIAL_PERMISSION_PREMIUM_SMS_ASK = 778;
+
+ // ACTION: "Premium SMS access" for an app - "never allow" option
+ APP_SPECIAL_PERMISSION_PREMIUM_SMS_DENY = 779;
+
+ // ACTION: "Premium SMS access" for an app - "always allow" option
+ APP_SPECIAL_PERMISSION_PREMIUM_SMS_ALWAYS_ALLOW = 780;
+
+ // ACTION: Allow "Unrestricted data access" for an app
+ APP_SPECIAL_PERMISSION_UNL_DATA_ALLOW = 781;
+
+ // ACTION: Deny "Unrestricted data access" for an app
+ APP_SPECIAL_PERMISSION_UNL_DATA_DENY = 782;
+
+ // ACTION: Allow "Usage access" for an app
+ APP_SPECIAL_PERMISSION_USAGE_VIEW_ALLOW = 783;
+
+ // ACTION: Deny "Usage access" for an app
+ APP_SPECIAL_PERMISSION_USAGE_VIEW_DENY = 784;
+
// ---- End O Constants, all O constants go above this line ----
+ // OPEN: QS NFC tile shown
+ // ACTION: QS NFC tile tapped
+ // CATEGORY: QUICK_SETTINGS
+ QS_NFC = 800;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 87f4030..fbb39384 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -25,6 +25,7 @@
import com.android.internal.inputmethod.InputMethodSubtypeHandle;
import com.android.internal.os.SomeArgs;
import com.android.internal.R;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
@@ -1700,6 +1701,7 @@
// Binder call
@Override
public void setCustomPointerIcon(PointerIcon icon) {
+ Preconditions.checkNotNull(icon);
nativeSetCustomPointerIcon(mPtr, icon);
}
diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
index c48f430..ee00fdc 100644
--- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
+++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
@@ -17,6 +17,8 @@
package com.android.server.net;
import android.net.NetworkIdentity;
+import android.service.NetworkIdentitySetProto;
+import android.util.proto.ProtoOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -143,4 +145,14 @@
final NetworkIdentity anotherIdent = another.iterator().next();
return ident.compareTo(anotherIdent);
}
+
+ public void writeToProto(ProtoOutputStream proto, long tag) {
+ final long start = proto.start(tag);
+
+ for (NetworkIdentity ident : this) {
+ ident.writeToProto(proto, NetworkIdentitySetProto.IDENTITIES);
+ }
+
+ proto.end(start);
+ }
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index c45b416..0354300 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -34,9 +34,13 @@
import android.net.NetworkTemplate;
import android.net.TrafficStats;
import android.os.Binder;
+import android.service.NetworkStatsCollectionKeyProto;
+import android.service.NetworkStatsCollectionProto;
+import android.service.NetworkStatsCollectionStatsProto;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.IntArray;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
@@ -532,12 +536,15 @@
/ mBucketDuration);
}
- public void dump(IndentingPrintWriter pw) {
+ private ArrayList<Key> getSortedKeys() {
final ArrayList<Key> keys = Lists.newArrayList();
keys.addAll(mStats.keySet());
Collections.sort(keys);
+ return keys;
+ }
- for (Key key : keys) {
+ public void dump(IndentingPrintWriter pw) {
+ for (Key key : getSortedKeys()) {
pw.print("ident="); pw.print(key.ident.toString());
pw.print(" uid="); pw.print(key.uid);
pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
@@ -550,6 +557,29 @@
}
}
+ public void writeToProto(ProtoOutputStream proto, long tag) {
+ final long start = proto.start(tag);
+
+ for (Key key : getSortedKeys()) {
+ final long startStats = proto.start(NetworkStatsCollectionProto.STATS);
+
+ // Key
+ final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY);
+ key.ident.writeToProto(proto, NetworkStatsCollectionKeyProto.IDENTITY);
+ proto.write(NetworkStatsCollectionKeyProto.UID, key.uid);
+ proto.write(NetworkStatsCollectionKeyProto.SET, key.set);
+ proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag);
+ proto.end(startKey);
+
+ // Value
+ final NetworkStatsHistory history = mStats.get(key);
+ history.writeToProto(proto, NetworkStatsCollectionStatsProto.HISTORY);
+ proto.end(startStats);
+ }
+
+ proto.end(start);
+ }
+
public void dumpCheckin(PrintWriter pw, long start, long end) {
dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell");
dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi");
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 090a076..80309e1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -29,9 +29,11 @@
import android.net.NetworkTemplate;
import android.net.TrafficStats;
import android.os.DropBoxManager;
+import android.service.NetworkStatsRecorderProto;
import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.net.VpnInfo;
import com.android.internal.util.FileRotator;
@@ -465,6 +467,15 @@
}
}
+ public void writeToProtoLocked(ProtoOutputStream proto, long tag) {
+ final long start = proto.start(tag);
+ if (mPending != null) {
+ proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes());
+ }
+ getOrLoadCompleteLocked().writeToProto(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY);
+ proto.end(start);
+ }
+
public void dumpCheckin(PrintWriter pw, long start, long end) {
// Only load and dump stats from the requested window
getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 386e78b..104c296 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -104,6 +104,8 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
+import android.service.NetworkInterfaceProto;
+import android.service.NetworkStatsServiceDumpProto;
import android.telephony.TelephonyManager;
import android.text.format.DateUtils;
import android.util.ArrayMap;
@@ -115,6 +117,7 @@
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.TrustedTime;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.net.VpnInfo;
@@ -1255,6 +1258,12 @@
final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " ");
synchronized (mStatsLock) {
+ if (args.length > 0 && "--proto".equals(args[0])) {
+ // In this case ignore all other arguments.
+ dumpProto(fd);
+ return;
+ }
+
if (poll) {
performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
pw.println("Forced poll");
@@ -1327,6 +1336,33 @@
}
}
+ private void dumpProto(FileDescriptor fd) {
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+ // TODO Right now it writes all history. Should it limit to the "since-boot" log?
+
+ dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces);
+ dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces);
+ mDevRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS);
+ mXtRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.XT_STATS);
+ mUidRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_STATS);
+ mUidTagRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS);
+
+ proto.flush();
+ }
+
+ private static void dumpInterfaces(ProtoOutputStream proto, long tag,
+ ArrayMap<String, NetworkIdentitySet> ifaces) {
+ for (int i = 0; i < ifaces.size(); i++) {
+ final long start = proto.start(tag);
+
+ proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i));
+ ifaces.valueAt(i).writeToProto(proto, NetworkInterfaceProto.IDENTITIES);
+
+ proto.end(start);
+ }
+ }
+
/**
* Return snapshot of current UID statistics, including any
* {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values.
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index d25abbf..d516acf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -145,6 +145,7 @@
private static final String ATTR_ABI_OVERRIDE = "abiOverride";
private static final String ATTR_VOLUME_UUID = "volumeUuid";
private static final String ATTR_NAME = "name";
+ private static final String ATTR_INSTALL_REASON = "installRason";
/** Automatically destroy sessions older than this */
private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
@@ -412,6 +413,7 @@
params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
params.grantedRuntimePermissions = readGrantedRuntimePermissions(in);
+ params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
final File appIconFile = buildAppIconFile(sessionId);
if (appIconFile.exists()) {
@@ -484,6 +486,7 @@
writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
+ writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
// Persist app icon if changed since last written
final File appIconFile = buildAppIconFile(session.sessionId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f10e8cb..c793f49 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12216,6 +12216,67 @@
mHandler.sendMessage(msg);
}
+
+ /**
+ * Ensure that the install reason matches what we know about the package installer (e.g. whether
+ * it is acting on behalf on an enterprise or the user).
+ *
+ * Note that the ordering of the conditionals in this method is important. The checks we perform
+ * are as follows, in this order:
+ *
+ * 1) If the install is being performed by a system app, we can trust the app to have set the
+ * install reason correctly. Thus, we pass through the install reason unchanged, no matter
+ * what it is.
+ * 2) If the install is being performed by a device or profile owner app, the install reason
+ * should be enterprise policy. However, we cannot be sure that the device or profile owner
+ * set the install reason correctly. If the app targets an older SDK version where install
+ * reasons did not exist yet, or if the app author simply forgot, the install reason may be
+ * unset or wrong. Thus, we force the install reason to be enterprise policy.
+ * 3) In all other cases, the install is being performed by a regular app that is neither part
+ * of the system nor a device or profile owner. We have no reason to believe that this app is
+ * acting on behalf of the enterprise admin. Thus, we check whether the install reason was
+ * set to enterprise policy and if so, change it to unknown instead.
+ */
+ private int fixUpInstallReason(String installerPackageName, int installerUid,
+ int installReason) {
+ if (checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
+ == PERMISSION_GRANTED) {
+ // If the install is being performed by a system app, we trust that app to have set the
+ // install reason correctly.
+ return installReason;
+ }
+
+ final IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
+ ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+ if (dpm != null) {
+ ComponentName owner = null;
+ try {
+ owner = dpm.getDeviceOwnerComponent(true /* callingUserOnly */);
+ if (owner == null) {
+ owner = dpm.getProfileOwner(UserHandle.getUserId(installerUid));
+ }
+ } catch (RemoteException e) {
+ }
+ if (owner != null && owner.getPackageName().equals(installerPackageName)) {
+ // If the install is being performed by a device or profile owner, the install
+ // reason should be enterprise policy.
+ return PackageManager.INSTALL_REASON_POLICY;
+ }
+ }
+
+ if (installReason == PackageManager.INSTALL_REASON_POLICY) {
+ // If the install is being performed by a regular app (i.e. neither system app nor
+ // device or profile owner), we have no reason to believe that the app is acting on
+ // behalf of an enterprise. If the app set the install reason to enterprise policy,
+ // change it to unknown instead.
+ return PackageManager.INSTALL_REASON_UNKNOWN;
+ }
+
+ // If the install is being performed by a regular app and the install reason was set to any
+ // value but enterprise policy, leave the install reason unchanged.
+ return installReason;
+ }
+
void installStage(String packageName, File stagedDir, String stagedCid,
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
String installerPackageName, int installerUid, UserHandle user,
@@ -12237,10 +12298,12 @@
}
final Message msg = mHandler.obtainMessage(INIT_COPY);
+ final int installReason = fixUpInstallReason(installerPackageName, installerUid,
+ sessionParams.installReason);
final InstallParams params = new InstallParams(origin, null, observer,
sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
verificationInfo, user, sessionParams.abiOverride,
- sessionParams.grantedRuntimePermissions, certificates, sessionParams.installReason);
+ sessionParams.grantedRuntimePermissions, certificates, installReason);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 27efd05..6791da9 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1462,7 +1462,11 @@
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
PointerIcon pointerIcon;
- android_view_PointerIcon_getLoadedIcon(env, iconObj, &pointerIcon);
+ status_t result = android_view_PointerIcon_getLoadedIcon(env, iconObj, &pointerIcon);
+ if (result) {
+ jniThrowRuntimeException(env, "Failed to load custom pointer icon.");
+ return;
+ }
SpriteIcon spriteIcon;
pointerIcon.bitmap.copyTo(&spriteIcon.bitmap, kN32_SkColorType);