summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt3
-rw-r--r--api/system-current.txt3
-rw-r--r--api/test-current.txt3
-rw-r--r--core/java/android/content/res/Configuration.java10
-rwxr-xr-xcore/java/android/provider/Settings.java3
-rw-r--r--core/java/android/widget/TextView.java4
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java25
-rw-r--r--core/java/com/android/internal/os/KernelWakelockReader.java29
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java147
-rw-r--r--docs/html/preview/features/afw.jd2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java13
-rw-r--r--packages/SystemUI/res/layout/navigation_bar.xml8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java37
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java17
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java17
-rw-r--r--services/core/java/com/android/server/notification/NotificationUsageStats.java89
-rw-r--r--services/core/java/com/android/server/notification/RateEstimator.java54
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java118
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java15
-rw-r--r--telecomm/java/android/telecom/Call.java7
23 files changed, 557 insertions, 100 deletions
diff --git a/api/current.txt b/api/current.txt
index 1a2774aa03c8..17182dbde4ce 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -36005,10 +36005,11 @@ package android.telecom {
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
field public static final int PROPERTY_CONFERENCE = 1; // 0x1
field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
+ field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_WIFI = 8; // 0x8
- field public static final int PROPERTY_WORK_CALL = 32; // 0x20
+ field public static final deprecated int PROPERTY_WORK_CALL = 32; // 0x20
}
public final class CallAudioState implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 0fb1826fda81..9bccb9ebc837 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -38841,10 +38841,11 @@ package android.telecom {
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
field public static final int PROPERTY_CONFERENCE = 1; // 0x1
field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
+ field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_WIFI = 8; // 0x8
- field public static final int PROPERTY_WORK_CALL = 32; // 0x20
+ field public static final deprecated int PROPERTY_WORK_CALL = 32; // 0x20
}
public static abstract deprecated class Call.Listener extends android.telecom.Call.Callback {
diff --git a/api/test-current.txt b/api/test-current.txt
index b14d60117488..13a96e013670 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -36082,10 +36082,11 @@ package android.telecom {
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
field public static final int PROPERTY_CONFERENCE = 1; // 0x1
field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
+ field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_WIFI = 8; // 0x8
- field public static final int PROPERTY_WORK_CALL = 32; // 0x20
+ field public static final deprecated int PROPERTY_WORK_CALL = 32; // 0x20
}
public final class CallAudioState implements android.os.Parcelable {
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 29e5b5db5b69..c1aac8584acb 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1485,6 +1485,16 @@ public final class Configuration implements Parcelable, Comparable<Configuration
}
/**
+ * @hide
+ *
+ * Clears the locale without changing layout direction.
+ */
+ public void clearLocales() {
+ mLocaleList = LocaleList.getEmptyLocaleList();
+ locale = null;
+ }
+
+ /**
* Return the layout direction. Will be either {@link View#LAYOUT_DIRECTION_LTR} or
* {@link View#LAYOUT_DIRECTION_RTL}.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 66d487fd3105..cbe98f7cd6e5 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2241,7 +2241,7 @@ public final class Settings {
public static void clearConfiguration(Configuration inoutConfig) {
inoutConfig.fontScale = 0;
if (!inoutConfig.userSetLocale && !inoutConfig.getLocales().isEmpty()) {
- inoutConfig.setLocales(LocaleList.getEmptyLocaleList());
+ inoutConfig.clearLocales();
}
}
@@ -3562,6 +3562,7 @@ public final class Settings {
DTMF_TONE_TYPE_WHEN_DIALING,
HEARING_AID,
TTY_MODE,
+ MASTER_MONO,
SOUND_EFFECTS_ENABLED,
HAPTIC_FEEDBACK_ENABLED,
POWER_SOUNDS_ENABLED, // moved to global
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a3eed70c47b6..fc120eb0e65f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1939,6 +1939,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
notifyViewAccessibilityStateChangedIfNeeded(
AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
+
+ // PasswordTransformationMethod always have LTR text direction heuristics returned by
+ // getTextDirectionHeuristic, needs reset
+ mTextDir = getTextDirectionHeuristic();
}
/**
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 937fc75046cb..93dc625f8846 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -8873,8 +8873,6 @@ public class BatteryStatsImpl extends BatteryStats {
return;
}
- // Record whether we've seen a non-zero time (for debugging b/22716723).
- boolean seenNonZeroTime = false;
for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
String name = ent.getKey();
KernelWakelockStats.Entry kws = ent.getValue();
@@ -8884,27 +8882,24 @@ public class BatteryStatsImpl extends BatteryStats {
kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase);
mKernelWakelockStats.put(name, kwlt);
}
+
kwlt.update(kws.mTotalTime, kws.mCount);
kwlt.setUpdateVersion(kws.mVersion);
-
- if (kws.mVersion != wakelockStats.kernelWakelockVersion) {
- seenNonZeroTime |= kws.mTotalTime > 0;
- }
}
int numWakelocksSetStale = 0;
- if (wakelockStats.size() != mKernelWakelockStats.size()) {
- // Set timers to stale if they didn't appear in /proc/wakelocks this time.
- for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
- SamplingTimer st = ent.getValue();
- if (st.getUpdateVersion() != wakelockStats.kernelWakelockVersion) {
- st.endSample();
- numWakelocksSetStale++;
- }
+ // Set timers to stale if they didn't appear in /d/wakeup_sources (or /proc/wakelocks)
+ // this time.
+ for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
+ SamplingTimer st = ent.getValue();
+ if (st.getUpdateVersion() != wakelockStats.kernelWakelockVersion) {
+ st.endSample();
+ numWakelocksSetStale++;
}
}
- if (!seenNonZeroTime) {
+ // Record whether we've seen a non-zero time (for debugging b/22716723).
+ if (wakelockStats.isEmpty()) {
Slog.wtf(TAG, "All kernel wakelocks had time of zero");
}
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index 6654ea5683e3..8036f257823b 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -18,6 +18,8 @@ package com.android.internal.os;
import android.os.Process;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.FileInputStream;
import java.util.Iterator;
@@ -106,14 +108,14 @@ public class KernelWakelockReader {
/**
* Reads the wakelocks and updates the staleStats with the new information.
*/
- private KernelWakelockStats parseProcWakelocks(byte[] wlBuffer, int len, boolean wakeup_sources,
- final KernelWakelockStats staleStats) {
+ @VisibleForTesting
+ public KernelWakelockStats parseProcWakelocks(byte[] wlBuffer, int len, boolean wakeup_sources,
+ final KernelWakelockStats staleStats) {
String name;
int count;
long totalTime;
int startIndex;
int endIndex;
- int numUpdatedWlNames = 0;
// Advance past the first line.
int i;
@@ -126,11 +128,10 @@ public class KernelWakelockReader {
for (endIndex=startIndex;
endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
endIndex++);
- endIndex++; // endIndex is an exclusive upper bound.
// Don't go over the end of the buffer, Process.parseProcLine might
// write to wlBuffer[endIndex]
- if (endIndex >= (len - 1) ) {
- return staleStats;
+ if (endIndex > (len - 1) ) {
+ break;
}
String[] nameStringArray = mProcWakelocksName;
@@ -161,7 +162,6 @@ public class KernelWakelockReader {
if (!staleStats.containsKey(name)) {
staleStats.put(name, new KernelWakelockStats.Entry(count, totalTime,
sKernelWakelockUpdateVersion));
- numUpdatedWlNames++;
} else {
KernelWakelockStats.Entry kwlStats = staleStats.get(name);
if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
@@ -171,7 +171,6 @@ public class KernelWakelockReader {
kwlStats.mCount = count;
kwlStats.mTotalTime = totalTime;
kwlStats.mVersion = sKernelWakelockUpdateVersion;
- numUpdatedWlNames++;
}
}
} else if (!parsed) {
@@ -182,16 +181,14 @@ public class KernelWakelockReader {
Slog.wtf(TAG, "Failed to parse proc line!");
}
}
- startIndex = endIndex;
+ startIndex = endIndex + 1;
}
- if (staleStats.size() != numUpdatedWlNames) {
- // Don't report old data.
- Iterator<KernelWakelockStats.Entry> itr = staleStats.values().iterator();
- while (itr.hasNext()) {
- if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
- itr.remove();
- }
+ // Don't report old data.
+ Iterator<KernelWakelockStats.Entry> itr = staleStats.values().iterator();
+ while (itr.hasNext()) {
+ if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
+ itr.remove();
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
new file mode 100644
index 000000000000..4e4bb350739d
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+package com.android.internal.os;
+
+import android.support.test.filters.SmallTest;
+
+import junit.framework.TestCase;
+
+import java.nio.charset.Charset;
+
+public class KernelWakelockReaderTest extends TestCase {
+ /**
+ * Helper class that builds the mock Kernel module file /d/wakeup_sources.
+ */
+ private static class ProcFileBuilder {
+ private final static String sHeader = "name\t\tactive_count\tevent_count\twakeup_count\t" +
+ "expire_count\tactive_since\ttotal_time\tmax_time\tlast_change\t" +
+ "prevent_suspend_time\n";
+
+ private StringBuilder mStringBuilder;
+
+ private void ensureHeader() {
+ if (mStringBuilder == null) {
+ mStringBuilder = new StringBuilder();
+ mStringBuilder.append(sHeader);
+ }
+ }
+
+ public ProcFileBuilder addLine(String name, int count, long timeMillis) {
+ ensureHeader();
+ mStringBuilder.append(name).append("\t").append(count).append("\t0\t0\t0\t0\t")
+ .append(timeMillis).append("\t0\t0\t0\n");
+ return this;
+ }
+
+ public byte[] getBytes() throws Exception {
+ ensureHeader();
+ byte[] data = mStringBuilder.toString().getBytes(Charset.forName("UTF-8"));
+
+ // The Kernel puts a \0 at the end of the data. Since each of our lines ends with \n,
+ // we override the last \n with a \0.
+ data[data.length - 1] = 0;
+ return data;
+ }
+ }
+
+ private KernelWakelockReader mReader;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mReader = new KernelWakelockReader();
+ }
+
+ @SmallTest
+ public void testParseEmptyFile() throws Exception {
+ KernelWakelockStats staleStats = mReader.parseProcWakelocks(new byte[0], 0, true,
+ new KernelWakelockStats());
+ assertTrue(staleStats.isEmpty());
+ }
+
+ @SmallTest
+ public void testOnlyHeader() throws Exception {
+ byte[] buffer = new ProcFileBuilder().getBytes();
+ KernelWakelockStats staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true,
+ new KernelWakelockStats());
+ assertTrue(staleStats.isEmpty());
+ }
+
+ @SmallTest
+ public void testOneWakelock() throws Exception {
+ byte[] buffer = new ProcFileBuilder()
+ .addLine("Wakelock", 34, 123) // Milliseconds
+ .getBytes();
+ KernelWakelockStats staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true,
+ new KernelWakelockStats());
+ assertEquals(1, staleStats.size());
+ assertTrue(staleStats.containsKey("Wakelock"));
+
+ KernelWakelockStats.Entry entry = staleStats.get("Wakelock");
+ assertEquals(34, entry.mCount);
+ assertEquals(123 * 1000, entry.mTotalTime); // Microseconds
+ }
+
+ @SmallTest
+ public void testTwoWakelocks() throws Exception {
+ byte[] buffer = new ProcFileBuilder()
+ .addLine("Wakelock", 1, 10)
+ .addLine("Fakelock", 2, 20)
+ .getBytes();
+ KernelWakelockStats staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true,
+ new KernelWakelockStats());
+ assertEquals(2, staleStats.size());
+ assertTrue(staleStats.containsKey("Wakelock"));
+ assertTrue(staleStats.containsKey("Fakelock"));
+ }
+
+ @SmallTest
+ public void testDuplicateWakelocksAccumulate() throws Exception {
+ byte[] buffer = new ProcFileBuilder()
+ .addLine("Wakelock", 1, 10) // Milliseconds
+ .addLine("Wakelock", 1, 10) // Milliseconds
+ .getBytes();
+ KernelWakelockStats staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true,
+ new KernelWakelockStats());
+ assertEquals(1, staleStats.size());
+ assertTrue(staleStats.containsKey("Wakelock"));
+
+ KernelWakelockStats.Entry entry = staleStats.get("Wakelock");
+ assertEquals(2, entry.mCount);
+ assertEquals(20 * 1000, entry.mTotalTime); // Microseconds
+ }
+
+ @SmallTest
+ public void testWakelocksBecomeStale() throws Exception {
+ byte[] buffer = new ProcFileBuilder()
+ .addLine("Fakelock", 3, 30)
+ .getBytes();
+ KernelWakelockStats staleStats = new KernelWakelockStats();
+
+ staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true, staleStats);
+ assertEquals(1, staleStats.size());
+ assertTrue(staleStats.containsKey("Fakelock"));
+
+ buffer = new ProcFileBuilder()
+ .addLine("Wakelock", 1, 10)
+ .getBytes();
+
+ staleStats = mReader.parseProcWakelocks(buffer, buffer.length, true, staleStats);
+ assertEquals(1, staleStats.size());
+ assertTrue(staleStats.containsKey("Wakelock"));
+ assertFalse(staleStats.containsKey("Fakelock"));
+ }
+}
diff --git a/docs/html/preview/features/afw.jd b/docs/html/preview/features/afw.jd
index dc53bd977f2f..9b94c079cb92 100644
--- a/docs/html/preview/features/afw.jd
+++ b/docs/html/preview/features/afw.jd
@@ -515,7 +515,7 @@ Android N.</p>
<p>
The dialer should check for the new flag
- <code>android.telecom.Call.PROPERTY_WORK_CALL</code> to determine if a call
+ <code>android.telecom.Call.PROPERTY_ENTERPRISE_CALL</code> to determine if a call
is a work call. If a call is a work call, the dialer should indicate this,
such as by adding a work badge.
</p>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 029a1259cd1b..f8fb1e579446 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -329,7 +329,8 @@ public class SettingsBackupAgent extends BackupAgentHelper {
final HashSet<Network> mKnownNetworks = new HashSet<Network>();
final ArrayList<Network> mNetworks = new ArrayList<Network>(8);
- public void readNetworks(BufferedReader in, List<WifiConfiguration> whitelist) {
+ public void readNetworks(BufferedReader in, List<WifiConfiguration> whitelist,
+ boolean acceptEapNetworks) {
try {
String line;
while (in.ready()) {
@@ -348,7 +349,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
}
// Don't propagate EAP network definitions
- if (net.isEap) {
+ if (net.isEap && !acceptEapNetworks) {
if (DEBUG_BACKUP) {
Log.v(TAG, "Skipping EAP network " + net.ssid + " / " + net.key_mgmt);
}
@@ -1176,7 +1177,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
WifiNetworkSettings fromFile = new WifiNetworkSettings();
br = new BufferedReader(new FileReader(file));
- fromFile.readNetworks(br, configs);
+ fromFile.readNetworks(br, configs, false);
// Write the parsed networks into a packed byte array
if (fromFile.mKnownNetworks.size() > 0) {
@@ -1204,7 +1205,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
if (supplicantFile.exists()) {
// Retain the existing APs; we'll append the restored ones to them
BufferedReader in = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT));
- supplicantImage.readNetworks(in, null);
+ supplicantImage.readNetworks(in, null, true);
in.close();
supplicantFile.delete();
@@ -1215,7 +1216,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
char[] restoredAsBytes = new char[size];
for (int i = 0; i < size; i++) restoredAsBytes[i] = (char) bytes[i];
BufferedReader in = new BufferedReader(new CharArrayReader(restoredAsBytes));
- supplicantImage.readNetworks(in, null);
+ supplicantImage.readNetworks(in, null, false);
if (DEBUG_BACKUP) {
Log.v(TAG, "Final AP list:");
@@ -1371,4 +1372,4 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
return WifiManager.WIFI_STATE_UNKNOWN;
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 36e937d4d3ef..8ba4c9c05ba6 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -27,12 +27,6 @@
<com.android.systemui.statusbar.phone.NavigationBarInflaterView
android:id="@+id/navigation_inflater"
android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <include android:id="@+id/rot0" layout="@layout/navigation_layout" />
-
- <include android:id="@+id/rot90" layout="@layout/navigation_layout_rot90" />
-
- </com.android.systemui.statusbar.phone.NavigationBarInflaterView>
+ android:layout_height="match_parent" />
</com.android.systemui.statusbar.phone.NavigationBarView>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index eaf375eefdb0..61a92b468b48 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -142,11 +142,9 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
}
}
mTileDividerIndex = mTiles.size();
- if (mOtherTiles.size() != 0) {
- mTiles.add(null);
- }
+ mTiles.add(null);
mTiles.addAll(mOtherTiles);
- mEditIndex = mTiles.indexOf(null);
+ updateDividerLocations();
notifyDataSetChanged();
}
@@ -203,6 +201,8 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
@Override
public void onBindViewHolder(final Holder holder, int position) {
if (holder.getItemViewType() == TYPE_DIVIDER) {
+ holder.itemView.setVisibility(mTileDividerIndex < mTiles.size() - 1 ? View.VISIBLE
+ : View.INVISIBLE);
return;
}
if (holder.getItemViewType() == TYPE_EDIT) {
@@ -340,9 +340,8 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
to = mTileDividerIndex;
}
} else {
- if (mTileDividerIndex == mTiles.size()) {
- notifyItemInserted(mTiles.size());
- mTiles.add(null);
+ if (mTileDividerIndex == mTiles.size() - 1) {
+ notifyItemChanged(mTileDividerIndex);
}
if (to <= mTileDividerIndex) {
to = mTileDividerIndex;
@@ -351,7 +350,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
} else {
if (to > mEditIndex) {
// Don't allow tiles to be dragged around when they aren't added.
- return false;
+ to = from;
}
// Allow the case where to == mEditIndex to fall through and swap which
// side the tile is currently on.
@@ -362,6 +361,9 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
CharSequence fromLabel = mTiles.get(from).state.label;
move(from, to, mTiles);
updateDividerLocations();
+ if (to == from) {
+ return true;
+ }
CharSequence announcement;
if (to >= mEditIndex) {
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE_SPEC,
@@ -405,12 +407,11 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
}
}
if (mTiles.size() - 1 == mTileDividerIndex) {
- mTiles.remove(mTiles.size() - 1);
- notifyItemRemoved(mTiles.size());
+ notifyItemChanged(mTileDividerIndex);
}
}
- private String strip(TileInfo tileInfo) {
+ private static String strip(TileInfo tileInfo) {
String spec = tileInfo.spec;
if (spec.startsWith(CustomTile.PREFIX)) {
ComponentName component = CustomTile.getComponentFromSpec(spec);
@@ -420,8 +421,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
}
private <T> void move(int from, int to, List<T> list) {
- list.add(from > to ? to : to + 1, list.get(from));
- list.remove(from > to ? from + 1 : from);
+ list.add(to, list.remove(from));
notifyItemMoved(from, to);
notifyItemChanged(to);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 4ec36f608111..2bee816b0539 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -24,7 +24,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Space;
import com.android.systemui.R;
@@ -90,6 +89,7 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi
if (mDensity != newConfig.densityDpi) {
mDensity = newConfig.densityDpi;
createInflaters();
+ inflateChildren();
clearViews();
inflateLayout(mCurrentLayout);
}
@@ -98,12 +98,25 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mRot0 = (FrameLayout) findViewById(R.id.rot0);
- mRot90 = (FrameLayout) findViewById(R.id.rot90);
+ inflateChildren();
clearViews();
inflateLayout(getDefaultLayout());
}
+ private void inflateChildren() {
+ removeAllViews();
+ mRot0 = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout, this, false);
+ mRot0.setId(R.id.rot0);
+ addView(mRot0);
+ mRot90 = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout_rot90, this,
+ false);
+ mRot90.setId(R.id.rot90);
+ addView(mRot90);
+ if (getParent() instanceof NavigationBarView) {
+ ((NavigationBarView) getParent()).updateRotatedViews();
+ }
+ }
+
protected String getDefaultLayout() {
return mContext.getString(R.string.config_navBarLayout);
}
@@ -123,9 +136,6 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi
@Override
public void onTuningChanged(String key, String newValue) {
if (NAV_BAR_VIEWS.equals(key)) {
- if (newValue == null) {
- newValue = getDefaultLayout();
- }
if (!Objects.equals(mCurrentLayout, newValue)) {
clearViews();
inflateLayout(newValue);
@@ -162,6 +172,9 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi
protected void inflateLayout(String newLayout) {
mCurrentLayout = newLayout;
+ if (newLayout == null) {
+ newLayout = getDefaultLayout();
+ }
String[] sets = newLayout.split(GRAVITY_SEPARATOR, 3);
String[] start = sets[0].split(BUTTON_SEPARATOR);
String[] center = sets[1].split(BUTTON_SEPARATOR);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 4b7d56b27169..5fab79692135 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -492,17 +492,7 @@ public class NavigationBarView extends LinearLayout {
@Override
public void onFinishInflate() {
- mRotatedViews[Surface.ROTATION_0] =
- mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
-
- mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
-
- mRotatedViews[Surface.ROTATION_270] = mRotatedViews[Surface.ROTATION_90];
-
- mCurrentView = mRotatedViews[Surface.ROTATION_0];
- for (int i = 0; i < mButtonDisatchers.size(); i++) {
- mButtonDisatchers.valueAt(i).setCurrentView(mCurrentView);
- }
+ updateRotatedViews();
((NavigationBarInflaterView) findViewById(R.id.navigation_inflater)).setButtonDispatchers(
mButtonDisatchers);
@@ -544,15 +534,16 @@ public class NavigationBarView extends LinearLayout {
}
}
- private void updateRecentsIcon() {
- getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
- }
+ void updateRotatedViews() {
+ mRotatedViews[Surface.ROTATION_0] =
+ mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
+ mRotatedViews[Surface.ROTATION_270] =
+ mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
- public boolean isVertical() {
- return mVertical;
+ updateCurrentView();
}
- public void reorient() {
+ private void updateCurrentView() {
final int rot = mDisplay.getRotation();
for (int i=0; i<4; i++) {
mRotatedViews[i].setVisibility(View.GONE);
@@ -563,6 +554,18 @@ public class NavigationBarView extends LinearLayout {
mButtonDisatchers.valueAt(i).setCurrentView(mCurrentView);
}
updateLayoutTransitionsEnabled();
+ }
+
+ private void updateRecentsIcon() {
+ getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
+ }
+
+ public boolean isVertical() {
+ return mVertical;
+ }
+
+ public void reorient() {
+ updateCurrentView();
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index ad57ae2cecb3..dc4d7b1d8a05 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1396,11 +1396,18 @@ class ActivityStarter {
final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
intentActivity = task != null ? task.getTopActivity() : null;
} else if (putIntoExistingTask) {
- // See if there is a task to bring to the front. If this is a SINGLE_INSTANCE
- // activity, there can be one and only one instance of it in the history, and it is
- // always in its own unique task, so we do a special search.
- intentActivity = mLaunchSingleInstance ? mSupervisor.findActivityLocked(mIntent, mStartActivity.info)
- : mSupervisor.findTaskLocked(mStartActivity);
+ if (mLaunchSingleInstance) {
+ // There can be one and only one instance of single instance activity in the
+ // history, and it is always in its own unique task, so we do a special search.
+ intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info);
+ } else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
+ // For the launch adjacent case we only want to put the activity in an existing
+ // task if the activity already exists in the history.
+ intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info);
+ } else {
+ // Otherwise find the best task to put the activity in.
+ intentActivity = mSupervisor.findTaskLocked(mStartActivity);
+ }
}
return intentActivity;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index fe6ecbd0a770..04be34a81579 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -92,6 +92,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -174,6 +175,7 @@ public class NotificationManagerService extends SystemService {
= SystemProperties.getBoolean("debug.child_notifs", true);
static final int MAX_PACKAGE_NOTIFICATIONS = 50;
+ static final float MAX_PACKAGE_ENQUEUE_RATE = 50f;
// message codes
static final int MESSAGE_TIMEOUT = 2;
@@ -216,6 +218,7 @@ public class NotificationManagerService extends SystemService {
/** notification_enqueue status value for an ignored notification. */
private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
+ private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
private String mRankerServicePackageName;
private IActivityManager mAm;
@@ -295,6 +298,7 @@ public class NotificationManagerService extends SystemService {
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
private RankingHandler mRankingHandler;
+ private long mLastOverRateLogTime;
private static class Archive {
final int mBufferSize;
@@ -2500,6 +2504,18 @@ public class NotificationManagerService extends SystemService {
// package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
if (!isSystemNotification && !isNotificationFromListener) {
synchronized (mNotificationList) {
+ final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
+ if (appEnqueueRate > MAX_PACKAGE_ENQUEUE_RATE) {
+ mUsageStats.registerOverRateQuota(pkg);
+ final long now = SystemClock.elapsedRealtime();
+ if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
+ Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
+ + ". Shedding events. package=" + pkg);
+ mLastOverRateLogTime = now;
+ }
+ return;
+ }
+
int count = 0;
final int N = mNotificationList.size();
for (int i=0; i<N; i++) {
@@ -2510,6 +2526,7 @@ public class NotificationManagerService extends SystemService {
}
count++;
if (count >= MAX_PACKAGE_NOTIFICATIONS) {
+ mUsageStats.registerOverCountQuota(pkg);
Slog.e(TAG, "Package has already posted " + count
+ " notifications. Not showing more. package=" + pkg);
return;
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index b853417ac0b3..00d7a7b9e0cb 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -29,6 +29,7 @@ import android.os.HandlerThread;
import android.os.Message;
import android.os.SystemClock;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Log;
import com.android.internal.logging.MetricsLogger;
@@ -74,6 +75,7 @@ public class NotificationUsageStats {
// Guarded by synchronized(this).
private final Map<String, AggregatedStats> mStats = new HashMap<>();
private final ArrayDeque<AggregatedStats[]> mStatsArrays = new ArrayDeque<>();
+ private ArraySet<String> mStatExpiredkeys = new ArraySet<>();
private final SQLiteLog mSQLiteLog;
private final Context mContext;
private final Handler mHandler;
@@ -102,12 +104,26 @@ public class NotificationUsageStats {
/**
* Called when a notification has been posted.
*/
+ public synchronized float getAppEnqueueRate(String packageName) {
+ AggregatedStats stats = getOrCreateAggregatedStatsLocked(packageName);
+ if (stats != null) {
+ return stats.getEnqueueRate(SystemClock.elapsedRealtime());
+ } else {
+ return 0f;
+ }
+ }
+
+ /**
+ * Called when a notification has been posted.
+ */
public synchronized void registerPostedByApp(NotificationRecord notification) {
- notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime();
+ final long now = SystemClock.elapsedRealtime();
+ notification.stats.posttimeElapsedMs = now;
AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
for (AggregatedStats stats : aggregatedStatsArray) {
stats.numPostedByApp++;
+ stats.updateInterarrivalEstimate(now);
stats.countApiUse(notification);
}
releaseAggregatedStatsLocked(aggregatedStatsArray);
@@ -124,6 +140,7 @@ public class NotificationUsageStats {
AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
for (AggregatedStats stats : aggregatedStatsArray) {
stats.numUpdatedByApp++;
+ stats.updateInterarrivalEstimate(SystemClock.elapsedRealtime());
stats.countApiUse(notification);
}
releaseAggregatedStatsLocked(aggregatedStatsArray);
@@ -206,18 +223,37 @@ public class NotificationUsageStats {
releaseAggregatedStatsLocked(aggregatedStatsArray);
}
+ public synchronized void registerOverRateQuota(String packageName) {
+ AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(packageName);
+ for (AggregatedStats stats : aggregatedStatsArray) {
+ stats.numRateViolations++;
+ }
+ }
+
+ public synchronized void registerOverCountQuota(String packageName) {
+ AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(packageName);
+ for (AggregatedStats stats : aggregatedStatsArray) {
+ stats.numQuotaViolations++;
+ }
+ }
+
// Locked by this.
private AggregatedStats[] getAggregatedStatsLocked(NotificationRecord record) {
+ return getAggregatedStatsLocked(record.sbn.getPackageName());
+ }
+
+ // Locked by this.
+ private AggregatedStats[] getAggregatedStatsLocked(String packageName) {
if (!ENABLE_AGGREGATED_IN_MEMORY_STATS) {
return EMPTY_AGGREGATED_STATS;
}
- // TODO: expand to package-level counts in the future.
AggregatedStats[] array = mStatsArrays.poll();
if (array == null) {
- array = new AggregatedStats[1];
+ array = new AggregatedStats[2];
}
array[0] = getOrCreateAggregatedStatsLocked(DEVICE_GLOBAL_STATS);
+ array[1] = getOrCreateAggregatedStatsLocked(packageName);
return array;
}
@@ -236,6 +272,7 @@ public class NotificationUsageStats {
result = new AggregatedStats(mContext, key);
mStats.put(key, result);
}
+ result.mLastAccessTime = SystemClock.elapsedRealtime();
return result;
}
@@ -272,6 +309,7 @@ public class NotificationUsageStats {
as.dump(pw, indent);
}
pw.println(indent + "mStatsArrays.size(): " + mStatsArrays.size());
+ pw.println(indent + "mStats.size(): " + mStats.size());
}
if (ENABLE_SQLITE_LOG) {
mSQLiteLog.dump(pw, indent, filter);
@@ -279,12 +317,20 @@ public class NotificationUsageStats {
}
public synchronized void emit() {
- // TODO: expand to package-level counts in the future.
AggregatedStats stats = getOrCreateAggregatedStatsLocked(DEVICE_GLOBAL_STATS);
stats.emit();
- mLastEmitTime = SystemClock.elapsedRealtime();
mHandler.removeMessages(MSG_EMIT);
mHandler.sendEmptyMessageDelayed(MSG_EMIT, EMIT_PERIOD);
+ for(String key: mStats.keySet()) {
+ if (mStats.get(key).mLastAccessTime < mLastEmitTime) {
+ mStatExpiredkeys.add(key);
+ }
+ }
+ for(String key: mStatExpiredkeys) {
+ mStats.remove(key);
+ }
+ mStatExpiredkeys.clear();
+ mLastEmitTime = SystemClock.elapsedRealtime();
}
/**
@@ -326,6 +372,10 @@ public class NotificationUsageStats {
public ImportanceHistogram noisyImportance;
public ImportanceHistogram quietImportance;
public ImportanceHistogram finalImportance;
+ public RateEstimator enqueueRate;
+ public int numRateViolations;
+ public int numQuotaViolations;
+ public long mLastAccessTime;
public AggregatedStats(Context context, String key) {
this.key = key;
@@ -334,6 +384,7 @@ public class NotificationUsageStats {
noisyImportance = new ImportanceHistogram(context, "note_imp_noisy_");
quietImportance = new ImportanceHistogram(context, "note_imp_quiet_");
finalImportance = new ImportanceHistogram(context, "note_importance_");
+ enqueueRate = new RateEstimator(mCreated);
}
public AggregatedStats getPrevious() {
@@ -444,6 +495,8 @@ public class NotificationUsageStats {
maybeCount("note_text", (numWithText - previous.numWithText));
maybeCount("note_sub_text", (numWithSubText - previous.numWithSubText));
maybeCount("note_info_text", (numWithInfoText - previous.numWithInfoText));
+ maybeCount("note_over_rate", (numRateViolations - previous.numRateViolations));
+ maybeCount("note_over_quota", (numQuotaViolations - previous.numQuotaViolations));
noisyImportance.maybeCount(previous.noisyImportance);
quietImportance.maybeCount(previous.quietImportance);
finalImportance.maybeCount(previous.finalImportance);
@@ -473,6 +526,8 @@ public class NotificationUsageStats {
previous.numWithText = numWithText;
previous.numWithSubText = numWithSubText;
previous.numWithInfoText = numWithInfoText;
+ previous.numRateViolations = numRateViolations;
+ previous.numQuotaViolations = numQuotaViolations;
noisyImportance.update(previous.noisyImportance);
quietImportance.update(previous.quietImportance);
finalImportance.update(previous.finalImportance);
@@ -493,6 +548,19 @@ public class NotificationUsageStats {
return toStringWithIndent("");
}
+ /** @return the enqueue rate if there were a new enqueue event right now. */
+ public float getEnqueueRate() {
+ return getEnqueueRate(SystemClock.elapsedRealtime());
+ }
+
+ public float getEnqueueRate(long now) {
+ return enqueueRate.getRate(now);
+ }
+
+ public void updateInterarrivalEstimate(long now) {
+ enqueueRate.update(now);
+ }
+
private String toStringWithIndent(String indent) {
StringBuilder output = new StringBuilder();
output.append(indent).append("AggregatedStats{\n");
@@ -549,6 +617,8 @@ public class NotificationUsageStats {
output.append("numWithSubText=").append(numWithSubText).append("\n");
output.append(indentPlusTwo);
output.append("numWithInfoText=").append(numWithInfoText).append("\n");
+ output.append("numRateViolations=").append(numRateViolations).append("\n");
+ output.append("numQuotaViolations=").append(numQuotaViolations).append("\n");
output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n");
output.append(indentPlusTwo).append(quietImportance.toString()).append("\n");
output.append(indentPlusTwo).append(finalImportance.toString()).append("\n");
@@ -586,6 +656,9 @@ public class NotificationUsageStats {
maybePut(dump, "numWithText", numWithText);
maybePut(dump, "numWithSubText", numWithSubText);
maybePut(dump, "numWithInfoText", numWithInfoText);
+ maybePut(dump, "numRateViolations", numRateViolations);
+ maybePut(dump, "numQuotaLViolations", numQuotaViolations);
+ maybePut(dump, "notificationEnqueueRate", getEnqueueRate());
noisyImportance.maybePut(dump, previous.noisyImportance);
quietImportance.maybePut(dump, previous.quietImportance);
finalImportance.maybePut(dump, previous.finalImportance);
@@ -598,6 +671,12 @@ public class NotificationUsageStats {
dump.put(name, value);
}
}
+
+ private void maybePut(JSONObject dump, String name, float value) throws JSONException {
+ if (value > 0.0) {
+ dump.put(name, value);
+ }
+ }
}
private static class ImportanceHistogram {
diff --git a/services/core/java/com/android/server/notification/RateEstimator.java b/services/core/java/com/android/server/notification/RateEstimator.java
new file mode 100644
index 000000000000..4dc30a4c98bd
--- /dev/null
+++ b/services/core/java/com/android/server/notification/RateEstimator.java
@@ -0,0 +1,54 @@
+/*
+ * 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
+ */
+
+package com.android.server.notification;
+
+
+/**
+ * Exponentially weighted moving average estimator for event rate.
+ *
+ * {@hide}
+ */
+public class RateEstimator {
+ private static final double RATE_ALPHA = 0.8;
+ private static final double MINIMUM_DT = 0.0005;
+ private long mLastEventTime;
+ private float mInterarrivalTime;
+
+ public RateEstimator(long now) {
+ mLastEventTime = now;
+ }
+
+ /** Update the estimate to account for an event that jsut happened. */
+ public float update(long now) {
+ mInterarrivalTime = (float) getInterarrivalEstimate(now);
+ mLastEventTime = now;
+ return (float) (1.0 / mInterarrivalTime);
+ }
+
+ /** @return the estimated rate if there were a new event right now. */
+ public float getRate(long now) {
+ return (float) (1.0 / getInterarrivalEstimate(now));
+ }
+
+ /** @return the average inter-arrival time if there were a new event right now. */
+ private double getInterarrivalEstimate(long now) {
+ // a*iat_old + (1-a)*(t_now-t_last)
+ double dt = ((double) (now - mLastEventTime)) / 1000.0;
+ dt = Math.max(dt, MINIMUM_DT);
+ return (RATE_ALPHA * mInterarrivalTime + (1.0 - RATE_ALPHA) * dt);
+ }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b30817f53cdb..b3c5743e239c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5411,7 +5411,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
errorIntent.setComponent(errorComponent);
errorIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
Intent.FLAG_RECEIVER_FOREGROUND);
- mContext.sendBroadcastAsUser(errorIntent, UserHandle.ALL);
+ mContext.sendBroadcastAsUser(errorIntent, UserHandle.CURRENT);
}
/** {@inheritDoc} */
diff --git a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
new file mode 100644
index 000000000000..cc0920f506a8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+package com.android.server.notification;
+
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class RateEstimatorTest extends AndroidTestCase {
+ private long mTestStartTime;
+ private RateEstimator mEstimator;
+
+ @Override
+ public void setUp() {
+ mTestStartTime = 1225731600000L;
+ mEstimator = new RateEstimator(mTestStartTime);
+ }
+
+ @SmallTest
+ public void testRunningTimeBackwardDoesntExplodeUpdate() throws Exception {
+ final float rate = mEstimator.update(mTestStartTime - 1000L);
+ assertFalse(Float.isInfinite(rate));
+ assertFalse(Float.isNaN(rate));
+ }
+
+ @SmallTest
+ public void testRunningTimeBackwardDoesntExplodeGet() throws Exception {
+ final float rate = mEstimator.getRate(mTestStartTime - 1000L);
+ assertFalse(Float.isInfinite(rate));
+ assertFalse(Float.isNaN(rate));
+ }
+
+ @SmallTest
+ public void testInstantaneousEventsDontExplodeUpdate() throws Exception {
+ final float rate = mEstimator.update(mTestStartTime);
+ assertFalse(Float.isInfinite(rate));
+ assertFalse(Float.isNaN(rate));
+ }
+
+ @SmallTest
+ public void testInstantaneousEventsDontExplodeGet() throws Exception {
+ final float rate = mEstimator.getRate(mTestStartTime);
+ assertFalse(Float.isInfinite(rate));
+ assertFalse(Float.isNaN(rate));
+ }
+
+ @SmallTest
+ public void testCompactBurstIsEstimatedUnderTwoPercent() throws Exception {
+ long eventStart = mTestStartTime + 1000; // start event a long time after initialization
+ long nextEventTime = postEvents(eventStart, 1, 5); // five events at 1000Hz
+ final float rate = mEstimator.getRate(nextEventTime);
+ assertLessThan("Rate", rate, 20f);
+ }
+
+ @SmallTest
+ public void testSustained1000HzBurstIsEstimatedOverNinetyPercent() throws Exception {
+ long eventStart = mTestStartTime + 1000; // start event a long time after initialization
+ long nextEventTime = postEvents(eventStart, 1, 100); // one hundred events at 1000Hz
+ final float rate = mEstimator.getRate(nextEventTime);
+ assertGreaterThan("Rate", rate, 900f);
+ }
+
+ @SmallTest
+ public void testSustained100HzBurstIsEstimatedOverNinetyPercent() throws Exception {
+ long eventStart = mTestStartTime + 1000; // start event a long time after initialization
+ long nextEventTime = postEvents(eventStart, 10, 100); // one hundred events at 100Hz
+ final float rate = mEstimator.getRate(nextEventTime);
+
+ assertGreaterThan("Rate", rate, 90f);
+ }
+
+ @SmallTest
+ public void testRecoverQuicklyAfterSustainedBurst() throws Exception {
+ long eventStart = mTestStartTime + 1000; // start event a long time after initialization
+ long nextEventTime = postEvents(eventStart, 10, 1000); // one hundred events at 100Hz
+ final float rate = mEstimator.getRate(nextEventTime + 5000L); // two seconds later
+ assertLessThan("Rate", rate, 2f);
+ }
+
+ @SmallTest
+ public void testEstimateShouldNotOvershoot() throws Exception {
+ long eventStart = mTestStartTime + 1000; // start event a long time after initialization
+ long nextEventTime = postEvents(eventStart, 1, 1000); // one thousand events at 1000Hz
+ final float rate = mEstimator.getRate(nextEventTime);
+ assertLessThan("Rate", rate, 1000f);
+ }
+
+ private void assertLessThan(String label, float a, float b) {
+ assertTrue(String.format("%s was %f, but should be less than %f", label, a, b), a < b);
+ }
+
+ private void assertGreaterThan(String label, float a, float b) {
+ assertTrue(String.format("%s was %f, but should be more than %f", label, a, b), a > b);
+ }
+
+ /** @returns the next event time. */
+ private long postEvents(long start, long dt, int num) {
+ long time = start;
+ for (int i = 0; i < num; i++) {
+ mEstimator.update(time);
+ time += dt;
+ }
+ return time;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 08cbcf764a4e..df9242dc0aa1 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -319,6 +319,7 @@ public class UsbDeviceManager {
// current USB state
private boolean mConnected;
private boolean mHostConnected;
+ private boolean mSourcePower;
private boolean mConfigured;
private boolean mUsbDataUnlocked;
private String mCurrentFunctions;
@@ -399,7 +400,8 @@ public class UsbDeviceManager {
public void updateHostState(UsbPort port, UsbPortStatus status) {
boolean hostConnected = status.getCurrentDataRole() == UsbPort.DATA_ROLE_HOST;
- obtainMessage(MSG_UPDATE_HOST_STATE, hostConnected ? 1 :0, 0).sendToTarget();
+ boolean sourcePower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE;
+ obtainMessage(MSG_UPDATE_HOST_STATE, hostConnected ? 1 :0, sourcePower ? 1 :0).sendToTarget();
}
private boolean waitForState(String state) {
@@ -717,6 +719,7 @@ public class UsbDeviceManager {
break;
case MSG_UPDATE_HOST_STATE:
mHostConnected = (msg.arg1 == 1);
+ mSourcePower = (msg.arg2 == 1);
updateUsbNotification();
if (mBootCompleted) {
updateUsbStateBroadcastIfNeeded();
@@ -782,7 +785,11 @@ public class UsbDeviceManager {
Resources r = mContext.getResources();
if (mConnected) {
if (!mUsbDataUnlocked) {
- id = com.android.internal.R.string.usb_charging_notification_title;
+ if (mSourcePower) {
+ id = com.android.internal.R.string.usb_supplying_notification_title;
+ } else {
+ id = com.android.internal.R.string.usb_charging_notification_title;
+ }
} else if (UsbManager.containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_MTP)) {
id = com.android.internal.R.string.usb_mtp_notification_title;
@@ -795,10 +802,12 @@ public class UsbDeviceManager {
} else if (UsbManager.containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
id = com.android.internal.R.string.usb_accessory_notification_title;
+ } else if (mSourcePower) {
+ id = com.android.internal.R.string.usb_supplying_notification_title;
} else {
id = com.android.internal.R.string.usb_charging_notification_title;
}
- } else if (mHostConnected) {
+ } else if (mSourcePower) {
id = com.android.internal.R.string.usb_supplying_notification_title;
}
if (id != mUsbNotificationId) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 39a12070a69b..43f8739f74fd 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -287,11 +287,16 @@ public final class Call {
public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
/**
- * Whether the call is associated with the work profile.
+ * @deprecated Use {@link #PROPERTY_ENTERPRISE_CALL} instead.
*/
public static final int PROPERTY_WORK_CALL = 0x00000020;
/**
+ * Whether the call is associated with the work profile.
+ */
+ public static final int PROPERTY_ENTERPRISE_CALL = 0x00000020;
+
+ /**
* When set, indicates that this {@code Call} does not actually exist locally for the
* {@link ConnectionService}.
* <p>