Merge "Flicker free screen-on from AOD" into oc-dr1-dev
diff --git a/Android.mk b/Android.mk
index cc34767..3b44255 100644
--- a/Android.mk
+++ b/Android.mk
@@ -247,6 +247,7 @@
core/java/android/nfc/INfcCardEmulation.aidl \
core/java/android/nfc/INfcFCardEmulation.aidl \
core/java/android/nfc/INfcUnlockHandler.aidl \
+ core/java/android/nfc/INfcDta.aidl \
core/java/android/nfc/ITagRemovedCallback.aidl \
core/java/android/os/IBatteryPropertiesListener.aidl \
core/java/android/os/IBatteryPropertiesRegistrar.aidl \
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index f991efe..6801618 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -29,6 +29,7 @@
import android.nfc.INfcFCardEmulation;
import android.nfc.INfcUnlockHandler;
import android.nfc.ITagRemovedCallback;
+import android.nfc.INfcDta;
import android.os.Bundle;
/**
@@ -40,7 +41,7 @@
INfcCardEmulation getNfcCardEmulationInterface();
INfcFCardEmulation getNfcFCardEmulationInterface();
INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
-
+ INfcDta getNfcDtaInterface(in String pkg);
int getState();
boolean disable(boolean saveState);
boolean enable();
diff --git a/core/java/android/nfc/INfcDta.aidl b/core/java/android/nfc/INfcDta.aidl
new file mode 100644
index 0000000..4cc5927
--- /dev/null
+++ b/core/java/android/nfc/INfcDta.aidl
@@ -0,0 +1,34 @@
+ /*
+ * Copyright (C) 2017 NXP Semiconductors
+ *
+ * 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.nfc;
+
+import android.os.Bundle;
+
+/**
+ * {@hide}
+ */
+interface INfcDta {
+
+ void enableDta();
+ void disableDta();
+ boolean enableServer(String serviceName, int serviceSap, int miu,
+ int rwSize,int testCaseId);
+ void disableServer();
+ boolean enableClient(String serviceName, int miu, int rwSize,
+ int testCaseId);
+ void disableClient();
+ boolean registerMessageService(String msgServiceName);
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 48869c7..debef63 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -16,8 +16,6 @@
package android.nfc;
-import java.util.HashMap;
-
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -43,6 +41,7 @@
import android.util.Log;
import java.io.IOException;
+import java.util.HashMap;
/**
* Represents the local NFC adapter.
@@ -627,6 +626,23 @@
}
/**
+ * Returns the binder interface to the NFC-DTA test interface.
+ * @hide
+ */
+ public INfcDta getNfcDtaInterface() {
+ if (mContext == null) {
+ throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
+ + " NFC extras APIs");
+ }
+ try {
+ return sService.getNfcDtaInterface(mContext.getPackageName());
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ return null;
+ }
+ }
+
+ /**
* NFC service dead - attempt best effort recovery
* @hide
*/
diff --git a/core/java/android/nfc/dta/NfcDta.java b/core/java/android/nfc/dta/NfcDta.java
new file mode 100644
index 0000000..8801662
--- /dev/null
+++ b/core/java/android/nfc/dta/NfcDta.java
@@ -0,0 +1,167 @@
+/*
+ * 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.nfc.dta;
+
+import android.content.Context;
+import android.nfc.INfcDta;
+import android.nfc.NfcAdapter;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * This class provides the primary API for DTA operations.
+ * @hide
+ */
+public final class NfcDta {
+ private static final String TAG = "NfcDta";
+
+ private static INfcDta sService;
+ private static HashMap<Context, NfcDta> sNfcDtas = new HashMap<Context, NfcDta>();
+
+ private final Context mContext;
+
+ private NfcDta(Context context, INfcDta service) {
+ mContext = context.getApplicationContext();
+ sService = service;
+ }
+
+ /**
+ * Helper to get an instance of this class.
+ *
+ * @param adapter A reference to an NfcAdapter object.
+ * @return
+ */
+ public static synchronized NfcDta getInstance(NfcAdapter adapter) {
+ if (adapter == null) throw new NullPointerException("NfcAdapter is null");
+ Context context = adapter.getContext();
+ if (context == null) {
+ Log.e(TAG, "NfcAdapter context is null.");
+ throw new UnsupportedOperationException();
+ }
+
+ NfcDta manager = sNfcDtas.get(context);
+ if (manager == null) {
+ INfcDta service = adapter.getNfcDtaInterface();
+ if (service == null) {
+ Log.e(TAG, "This device does not implement the INfcDta interface.");
+ throw new UnsupportedOperationException();
+ }
+ manager = new NfcDta(context, service);
+ sNfcDtas.put(context, manager);
+ }
+ return manager;
+ }
+
+ /**
+ * Enables DTA mode
+ *
+ * @return true/false if enabling was successful
+ */
+ public boolean enableDta() {
+ try {
+ sService.enableDta();
+ } catch (RemoteException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Disables DTA mode
+ *
+ * @return true/false if disabling was successful
+ */
+ public boolean disableDta() {
+ try {
+ sService.disableDta();
+ } catch (RemoteException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Enables Server
+ *
+ * @return true/false if enabling was successful
+ */
+ public boolean enableServer(String serviceName, int serviceSap, int miu,
+ int rwSize, int testCaseId) {
+ try {
+ return sService.enableServer(serviceName, serviceSap, miu, rwSize, testCaseId);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Disables Server
+ *
+ * @return true/false if disabling was successful
+ */
+ public boolean disableServer() {
+ try {
+ sService.disableServer();
+ } catch (RemoteException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Enables Client
+ *
+ * @return true/false if enabling was successful
+ */
+ public boolean enableClient(String serviceName, int miu, int rwSize,
+ int testCaseId) {
+ try {
+ return sService.enableClient(serviceName, miu, rwSize, testCaseId);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Disables client
+ *
+ * @return true/false if disabling was successful
+ */
+ public boolean disableClient() {
+ try {
+ sService.disableClient();
+ } catch (RemoteException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Registers Message Service
+ *
+ * @return true/false if registration was successful
+ */
+ public boolean registerMessageService(String msgServiceName) {
+ try {
+ return sService.registerMessageService(msgServiceName);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+}
diff --git a/core/java/android/util/AtomicFile.java b/core/java/android/util/AtomicFile.java
index 2f1abe9..0122e49 100644
--- a/core/java/android/util/AtomicFile.java
+++ b/core/java/android/util/AtomicFile.java
@@ -202,6 +202,15 @@
}
/**
+ * @hide
+ * Checks if the original or backup file exists.
+ * @return whether the original or backup file exists.
+ */
+ public boolean exists() {
+ return mBaseName.exists() || mBackupName.exists();
+ }
+
+ /**
* Gets the last modified time of the atomic file.
* {@hide}
*
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a19f05c..cac27af 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -729,7 +729,7 @@
mLocation[1] = getHeight();
mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
- mLocation[0], mLocation[1]);
+ mWindowSpaceLeft + mLocation[0], mWindowSpaceTop + mLocation[1]);
if (mTranslator != null) {
mTranslator.translateRectInAppWindowToScreen(mScreenRect);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index ec3b520..0400e24 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1065,7 +1065,7 @@
// are still seen, we will investigate further.
update(config); // Notifies the AccessPointListener of the change
}
- if (mRssi != info.getRssi()) {
+ if (mRssi != info.getRssi() && info.getRssi() != WifiInfo.INVALID_RSSI) {
mRssi = info.getRssi();
updated = true;
} else if (mNetworkInfo != null && networkInfo != null
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 9ccd332..5a35da9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -365,7 +365,7 @@
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
mRegistered = false;
}
- unregisterAndClearScoreCache();
+ unregisterScoreCache();
pauseScanning();
mContext.getContentResolver().unregisterContentObserver(mObserver);
@@ -375,11 +375,14 @@
mStaleScanResults = true;
}
- private void unregisterAndClearScoreCache() {
+ private void unregisterScoreCache() {
mNetworkScoreManager.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, mScoreCache);
- mScoreCache.clearScores();
- // Synchronize on mLock to avoid concurrent modification during updateAccessPoints
+ // We do not want to clear the existing scores in the cache, as this method is called during
+ // stop tracking on activity pause. Hence, on resumption we want the ability to show the
+ // last known, potentially stale, scores. However, by clearing requested scores, the scores
+ // will be requested again upon resumption of tracking, and if any changes have occurred
+ // the listeners (UI) will be updated accordingly.
synchronized (mLock) {
mRequestedScores.clear();
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index c08dd6e..2f02b9b 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -626,6 +626,57 @@
}
@Test
+ public void testUpdateWithDifferentRssi_returnsTrue() {
+ int networkId = 123;
+ int rssi = -55;
+ WifiConfiguration config = new WifiConfiguration();
+ config.networkId = networkId;
+ WifiInfo wifiInfo = new WifiInfo();
+ wifiInfo.setNetworkId(networkId);
+ wifiInfo.setRssi(rssi);
+
+ NetworkInfo networkInfo =
+ new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
+ networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
+
+ AccessPoint ap = new TestAccessPointBuilder(mContext)
+ .setNetworkInfo(networkInfo)
+ .setNetworkId(networkId)
+ .setRssi(rssi)
+ .setWifiInfo(wifiInfo)
+ .build();
+
+ NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
+ wifiInfo.setRssi(rssi + 1);
+ assertThat(ap.update(config, wifiInfo, newInfo)).isTrue();
+ }
+
+ @Test
+ public void testUpdateWithInvalidRssi_returnsFalse() {
+ int networkId = 123;
+ int rssi = -55;
+ WifiConfiguration config = new WifiConfiguration();
+ config.networkId = networkId;
+ WifiInfo wifiInfo = new WifiInfo();
+ wifiInfo.setNetworkId(networkId);
+ wifiInfo.setRssi(rssi);
+
+ NetworkInfo networkInfo =
+ new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
+ networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
+
+ AccessPoint ap = new TestAccessPointBuilder(mContext)
+ .setNetworkInfo(networkInfo)
+ .setNetworkId(networkId)
+ .setRssi(rssi)
+ .setWifiInfo(wifiInfo)
+ .build();
+
+ NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
+ wifiInfo.setRssi(WifiInfo.INVALID_RSSI);
+ assertThat(ap.update(config, wifiInfo, newInfo)).isFalse();
+ }
+ @Test
public void testUpdateWithConfigChangeOnly_returnsFalseButInvokesListener() {
int networkId = 123;
int rssi = -55;
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index b6d0c45..c87d01a 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -473,6 +473,17 @@
}
@Test
+ public void stopTracking_shouldNotClearExistingScores()
+ throws InterruptedException {
+ // Start the tracker and inject the initial scan results and then stop tracking
+ WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
+ updateScoresAndWaitForAccessPointsChangedCallback(tracker);
+ tracker.stopTracking();
+
+ assertThat(mScoreCacheCaptor.getValue().getScoredNetwork(NETWORK_KEY_1)).isNotNull();
+ }
+
+ @Test
public void scoreCacheUpdateScoresShouldTriggerOnAccessPointsChanged()
throws InterruptedException {
WifiTracker tracker = createMockedWifiTracker();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index f5d7dd8..ad2ec0b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2597,7 +2597,7 @@
synchronized (mLock) {
final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
File globalFile = getSettingsFile(key);
- if (globalFile.exists()) {
+ if (SettingsState.stateFileExists(globalFile)) {
return;
}
@@ -2634,7 +2634,7 @@
// Every user has secure settings and if no file we need to migrate.
final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
File secureFile = getSettingsFile(secureKey);
- if (secureFile.exists()) {
+ if (SettingsState.stateFileExists(secureFile)) {
return;
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 5f4b239..d3ac11a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -689,17 +689,11 @@
private void readStateSyncLocked() {
FileInputStream in;
- if (!mStatePersistFile.exists()) {
- Slog.i(LOG_TAG, "No settings state " + mStatePersistFile);
- addHistoricalOperationLocked(HISTORICAL_OPERATION_INITIALIZE, null);
- return;
- }
try {
in = new AtomicFile(mStatePersistFile).openRead();
} catch (FileNotFoundException fnfe) {
- String message = "No settings state " + mStatePersistFile;
- Slog.wtf(LOG_TAG, message);
- Slog.i(LOG_TAG, message);
+ Slog.i(LOG_TAG, "No settings state " + mStatePersistFile);
+ addHistoricalOperationLocked(HISTORICAL_OPERATION_INITIALIZE, null);
return;
}
try {
@@ -715,6 +709,16 @@
}
}
+ /**
+ * Uses AtomicFile to check if the file or its backup exists.
+ * @param file The file to check for existence
+ * @return whether the original or backup exist
+ */
+ public static boolean stateFileExists(File file) {
+ AtomicFile stateFile = new AtomicFile(file);
+ return stateFile.exists();
+ }
+
private void parseStateLocked(XmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index f5efcaa..56fb73f 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -31,7 +31,7 @@
android:layout_height="wrap_content"
android:textColor="?attr/wallpaperTextColor"
style="@style/widget_label"
- android:letterSpacing="0.15"
+ android:letterSpacing="0.05"
android:gravity="center"
/>
<TextView android:id="@+id/alarm_status"
@@ -42,7 +42,7 @@
android:drawableTint="?attr/wallpaperTextColorSecondary"
android:drawableTintMode="src_in"
android:textColor="?attr/wallpaperTextColorSecondary"
- android:letterSpacing="0.15"
+ android:letterSpacing="0.05"
style="@style/widget_label"
android:layout_marginStart="6dp"
android:gravity="center"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1ff7ae4..94687de 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -101,6 +101,9 @@
<!-- Height of a the shelf with the notification icons -->
<dimen name="notification_shelf_height">32dp</dimen>
+ <!-- Minimum height of a notification to be interactable -->
+ <dimen name="notification_min_interaction_height">40dp</dimen>
+
<!-- the padding of the shelf icon container -->
<dimen name="shelf_icon_container_padding">13dp</dimen>
@@ -781,6 +784,9 @@
<!-- The shortest-edge size of the expanded PiP. -->
<dimen name="pip_expanded_shortest_edge_size">160dp</dimen>
+ <!-- The additional offset to apply to the IME animation to account for the input field. -->
+ <dimen name="pip_ime_offset">48dp</dimen>
+
<!-- The padding between actions in the PiP in landscape Note that the PiP does not reflect
the configuration of the device, so we can't use -land resources. -->
<dimen name="pip_between_action_padding_land">8dp</dimen>
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 278fdc3..d3be19d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -27,6 +27,7 @@
import android.app.IActivityManager;
import android.content.ComponentName;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -122,6 +123,7 @@
private boolean mIsMinimized;
private boolean mIsImeShowing;
private int mImeHeight;
+ private int mImeOffset;
private float mSavedSnapFraction = -1f;
private boolean mSendingHoverAccessibilityEvents;
private boolean mMovementWithinMinimize;
@@ -192,8 +194,11 @@
};
mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mMenuController,
mSnapAlgorithm, mFlingAnimationUtils);
- mExpandedShortestEdgeSize = context.getResources().getDimensionPixelSize(
+
+ Resources res = context.getResources();
+ mExpandedShortestEdgeSize = res.getDimensionPixelSize(
R.dimen.pip_expanded_shortest_edge_size);
+ mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset);
// Register the listener for input consumer touch events
inputConsumerController.setTouchListener(this::handleTouchEvent);
@@ -265,7 +270,6 @@
mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds, expandedMovementBounds,
mIsImeShowing ? mImeHeight : 0);
-
// If this is from an IME adjustment, then we should move the PiP so that it is not occluded
// by the IME
if (fromImeAdjustement) {
@@ -278,18 +282,22 @@
? expandedMovementBounds
: normalMovementBounds;
if (mIsImeShowing) {
- // IME visible
+ // IME visible, apply the IME offset if the space allows for it
+ final int imeOffset = toMovementBounds.bottom - Math.max(toMovementBounds.top,
+ toMovementBounds.bottom - mImeOffset);
if (bounds.top == mMovementBounds.bottom) {
// If the PIP is currently resting on top of the IME, then adjust it with
- // the hiding IME
- bounds.offsetTo(bounds.left, toMovementBounds.bottom);
+ // the showing IME
+ bounds.offsetTo(bounds.left, toMovementBounds.bottom - imeOffset);
} else {
- bounds.offset(0, Math.min(0, toMovementBounds.bottom - bounds.top));
+ bounds.offset(0, Math.min(0, toMovementBounds.bottom - imeOffset
+ - bounds.top));
}
} else {
// IME hidden
- if (bounds.top == mMovementBounds.bottom) {
- // If the PIP is resting on top of the IME, then adjust it with the hiding IME
+ if (bounds.top >= (mMovementBounds.bottom - mImeOffset)) {
+ // If the PIP is resting on top of the IME, then adjust it with the hiding
+ // IME
bounds.offsetTo(bounds.left, toMovementBounds.bottom);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index ed4f685..22c0b736 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1973,6 +1973,9 @@
if (mGuts != null) {
mGuts.setActualHeight(height);
}
+ if (mMenuRow.getMenuView() != null) {
+ mMenuRow.onHeightUpdate();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
index f859124..99b4b07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
@@ -100,6 +100,7 @@
private boolean mShouldShowMenu;
private NotificationSwipeActionHelper mSwipeHelper;
+ private boolean mIsUserTouching;
public NotificationMenuRow(Context context) {
mContext = context;
@@ -202,8 +203,11 @@
} else {
mIconsPlaced = false;
setMenuLocation();
- // If the # of items showing changed we need to update the snap position
- showMenu(mParent, mOnLeft ? getSpaceForMenu() : -getSpaceForMenu(), 0 /* velocity */);
+ if (!mIsUserTouching) {
+ // If the # of items showing changed we need to update the snap position
+ showMenu(mParent, mOnLeft ? getSpaceForMenu() : -getSpaceForMenu(),
+ 0 /* velocity */);
+ }
}
}
@@ -233,6 +237,7 @@
mHandler.removeCallbacks(mCheckForDrag);
mCheckForDrag = null;
mPrevX = ev.getRawX();
+ mIsUserTouching = true;
break;
case MotionEvent.ACTION_MOVE:
@@ -265,7 +270,12 @@
break;
case MotionEvent.ACTION_UP:
+ mIsUserTouching = false;
return handleUpEvent(ev, view, velocity);
+ case MotionEvent.ACTION_CANCEL:
+ mIsUserTouching = false;
+ cancelDrag();
+ return false;
}
return false;
}
@@ -354,23 +364,24 @@
}
private void snapBack(View animView, float velocity) {
- if (mFadeAnimator != null) {
- mFadeAnimator.cancel();
- }
- mHandler.removeCallbacks(mCheckForDrag);
+ cancelDrag();
mMenuSnappedTo = false;
mSnapping = true;
mSwipeHelper.snap(animView, 0 /* leftTarget */, velocity);
}
private void dismiss(View animView, float velocity) {
+ cancelDrag();
+ mMenuSnappedTo = false;
+ mDismissing = true;
+ mSwipeHelper.dismiss(animView, velocity);
+ }
+
+ private void cancelDrag() {
if (mFadeAnimator != null) {
mFadeAnimator.cancel();
}
mHandler.removeCallbacks(mCheckForDrag);
- mMenuSnappedTo = false;
- mDismissing = true;
- mSwipeHelper.dismiss(animView, velocity);
}
/**
@@ -420,7 +431,7 @@
if (mParent == null || mMenuItems.size() == 0 || mMenuContainer == null) {
return;
}
- int parentHeight = mParent.getCollapsedHeight();
+ int parentHeight = mParent.getActualHeight();
float translationY;
if (parentHeight < mVertSpaceForIcons) {
translationY = (parentHeight / 2) - (mHorizSpaceForIcon / 2);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index e5f68ad..1889806 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -244,7 +244,7 @@
boolean aboveShelf = ViewState.getFinalTranslationZ(row) > baseZHeight;
boolean isLastChild = child == lastChild;
float rowTranslationY = row.getTranslationY();
- if (isLastChild || aboveShelf || backgroundForceHidden) {
+ if ((isLastChild && !child.isInShelf()) || aboveShelf || backgroundForceHidden) {
notificationClipEnd = shelfStart + getIntrinsicHeight();
} else {
notificationClipEnd = shelfStart - mPaddingBetweenElements;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index c1581c8..881de67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -334,16 +334,18 @@
public void onOverlayChanged() {
@ColorInt int textColor = Utils.getColorAttr(mContext, R.attr.wallpaperTextColor);
- mCarrierLabel.setTextColor(textColor);
- mBatteryView.setFillColor(textColor);
- mIconManager.setTint(textColor);
-
+ @ColorInt int iconColor = Utils.getDefaultColor(mContext, Color.luminance(textColor) < 0.5 ?
+ R.color.dark_mode_icon_color_single_tone :
+ R.color.light_mode_icon_color_single_tone);
float intensity = textColor == Color.WHITE ? 0 : 1;
+ mCarrierLabel.setTextColor(iconColor);
+ mBatteryView.setFillColor(iconColor);
+ mIconManager.setTint(iconColor);
Rect tintArea = new Rect(0, 0, 0, 0);
- applyDarkness(R.id.signal_cluster, tintArea, intensity, textColor);
- applyDarkness(R.id.battery, tintArea, intensity, textColor);
- applyDarkness(R.id.clock, tintArea, intensity, textColor);
+ applyDarkness(R.id.signal_cluster, tintArea, intensity, iconColor);
+ applyDarkness(R.id.battery, tintArea, intensity, iconColor);
+ applyDarkness(R.id.clock, tintArea, intensity, iconColor);
}
private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
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 0097391..42cebe2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -369,6 +369,7 @@
private NotificationShelf mShelf;
private int mMaxDisplayedNotifications = -1;
private int mStatusBarHeight;
+ private int mMinInteractionHeight;
private boolean mNoAmbient;
private final Rect mClipRect = new Rect();
private boolean mIsClipped;
@@ -517,6 +518,8 @@
R.dimen.min_top_overscroll_to_qs);
mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height);
mBottomMargin = res.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom);
+ mMinInteractionHeight = res.getDimensionPixelSize(
+ R.dimen.notification_min_interaction_height);
}
public void setDrawBackgroundAsSrc(boolean asSrc) {
@@ -1079,7 +1082,7 @@
final int count = getChildCount();
for (int childIdx = 0; childIdx < count; childIdx++) {
ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx);
- if (slidingChild.getVisibility() == GONE
+ if (slidingChild.getVisibility() != VISIBLE
|| slidingChild instanceof StackScrollerDecorView) {
continue;
}
@@ -1093,7 +1096,8 @@
int left = 0;
int right = getWidth();
- if (touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) {
+ if (bottom - top >= mMinInteractionHeight
+ && touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) {
if (slidingChild instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
if (!mIsExpanded && row.isHeadsUp() && row.isPinned()
@@ -2005,6 +2009,7 @@
}
mContentHeight = height + mTopPadding + mBottomMargin;
updateScrollability();
+ clampScrollPosition();
mAmbientState.setLayoutMaxHeight(mContentHeight);
}
@@ -3463,7 +3468,7 @@
}
private void updateScrollPositionOnExpandInBottom(ExpandableView view) {
- if (view instanceof ExpandableNotificationRow) {
+ if (view instanceof ExpandableNotificationRow && !onKeyguard()) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
if (row.isUserLocked() && row != getFirstChildNotGone()) {
if (row.isSummaryWithChildren()) {
@@ -4344,10 +4349,10 @@
@Override
public void onDownUpdate(View currView, MotionEvent ev) {
mTranslatingParentView = currView;
- mCurrMenuRow = null;
if (mCurrMenuRow != null) {
mCurrMenuRow.onTouchEvent(currView, ev, 0 /* velocity */);
}
+ mCurrMenuRow = null;
mHandler.removeCallbacks(mFalsingCheck);
// Slide back any notifications that might be showing a menu
@@ -4358,6 +4363,7 @@
mCurrMenuRow = row.createMenu();
mCurrMenuRow.setSwipeActionHelper(NotificationSwipeHelper.this);
mCurrMenuRow.setMenuClickListener(NotificationStackScrollLayout.this);
+ mCurrMenuRow.onTouchEvent(currView, ev, 0 /* velocity */);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1f684aa..5a8ebc2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3828,13 +3828,6 @@
return true;
}
- // Suppressed for being too recently noisy
- final String pkg = record.sbn.getPackageName();
- if (mUsageStats.isAlertRateLimited(pkg)) {
- Slog.e(TAG, "Muting recently noisy " + record.getKey());
- return true;
- }
-
// muted by listener
final String disableEffects = disableNotificationEffects(record);
if (disableEffects != null) {
@@ -3852,6 +3845,13 @@
return notification.suppressAlertingDueToGrouping();
}
+ // Suppressed for being too recently noisy
+ final String pkg = record.sbn.getPackageName();
+ if (mUsageStats.isAlertRateLimited(pkg)) {
+ Slog.e(TAG, "Muting recently noisy " + record.getKey());
+ return true;
+ }
+
return false;
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index b9d02a9..63890bf 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -431,11 +431,18 @@
mEnteringAnimation = true;
mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token);
}
+
// If we are hidden but there is no delay needed we immediately
// apply the Surface transaction so that the ActivityManager
- // can have some guarantee on the Surface state
- // following setting the visibility.
- if (hidden && !delayed) {
+ // can have some guarantee on the Surface state following
+ // setting the visibility. This captures cases like dismissing
+ // the docked or pinned stack where there is no app transition.
+ //
+ // In the case of a "Null" animation, there will be
+ // no animation but there will still be a transition set.
+ // We still need to delay hiding the surface such that it
+ // can be synchronized with showing the next surface in the transition.
+ if (hidden && !delayed && !mService.mAppTransition.isTransitionSet()) {
SurfaceControl.openTransaction();
for (int i = mChildren.size() - 1; i >= 0; i--) {
mChildren.get(i).mWinAnimator.hide("immediately hidden");
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 807703b..b023126 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -831,6 +831,16 @@
}
@Test
+ public void testPostingGroupSuppressedDoesNotAffectRateLimiting() throws Exception {
+ NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN);
+ summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
+
+ mService.buzzBeepBlinkLocked(summary);
+
+ verify(mUsageStats, never()).isAlertRateLimited(any());
+ }
+
+ @Test
public void testCrossUserSoundMuted() throws Exception {
final Notification n = new Builder(getContext(), "test")
.setSmallIcon(android.R.drawable.sym_def_app_icon).build();
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
index 984a484..ea207f1 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
@@ -58,7 +58,7 @@
}
public void testTaskIdsPersistence() {
- SparseBooleanArray taskIdsOnFile = mTaskPersister.loadPersistedTaskIdsForUser(testUserId);
+ SparseBooleanArray taskIdsOnFile = new SparseBooleanArray();
for (int i = 0; i < 100; i++) {
taskIdsOnFile.put(getRandomTaskIdForUser(testUserId), true);
}
diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java
index 3282f5f..e64e815 100644
--- a/telephony/java/android/telephony/Telephony.java
+++ b/telephony/java/android/telephony/Telephony.java
@@ -2765,6 +2765,13 @@
public static final String USER_VISIBLE = "user_visible";
/**
+ * Is the user allowed to edit this APN?
+ * <p>Type: INTEGER (boolean) </p>
+ * @hide
+ */
+ public static final String USER_EDITABLE = "user_editable";
+
+ /**
* Following are possible values for the EDITED field
* @hide
*/