summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--api/system-current.txt1
-rw-r--r--api/test-current.txt1
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java2
-rw-r--r--core/java/android/app/Notification.java65
-rw-r--r--core/java/android/app/PendingIntent.java35
-rw-r--r--core/java/android/content/pm/IOtaDexopt.aidl7
-rw-r--r--core/java/android/os/Parcel.java37
-rw-r--r--core/java/android/util/ArraySet.java26
-rw-r--r--libs/hwui/LayerUpdateQueue.cpp1
-rw-r--r--libs/hwui/tests/unit/LayerUpdateQueueTests.cpp6
-rw-r--r--packages/MtpDocumentsProvider/res/values-af/strings.xml25
-rw-r--r--packages/MtpDocumentsProvider/res/values-sv/strings.xml25
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java4
-rw-r--r--services/core/java/com/android/server/AttributeCache.java27
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java15
-rwxr-xr-xservices/core/java/com/android/server/am/ActiveServices.java41
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java3
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java17
-rw-r--r--services/core/java/com/android/server/job/controllers/ContentObserverController.java40
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java39
-rw-r--r--services/core/java/com/android/server/pm/Installer.java7
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java161
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptShellCommand.java9
-rw-r--r--services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java78
-rw-r--r--telecomm/java/android/telecom/Connection.java15
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java15
30 files changed, 620 insertions, 101 deletions
diff --git a/api/current.txt b/api/current.txt
index f7b15ba9ed0f..53791405683c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -36771,6 +36771,7 @@ package android.telephony {
field public static final java.lang.String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
field public static final java.lang.String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
field public static final java.lang.String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
+ field public static final java.lang.String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
field public static final java.lang.String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
field public static final java.lang.String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
diff --git a/api/system-current.txt b/api/system-current.txt
index bf1842e85b0d..6a6653357d10 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -39810,6 +39810,7 @@ package android.telephony {
field public static final java.lang.String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
field public static final java.lang.String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
field public static final java.lang.String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
+ field public static final java.lang.String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
field public static final java.lang.String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
field public static final java.lang.String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
diff --git a/api/test-current.txt b/api/test-current.txt
index fa066224a47a..7642282f4aca 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -36849,6 +36849,7 @@ package android.telephony {
field public static final java.lang.String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
field public static final java.lang.String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
field public static final java.lang.String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
+ field public static final java.lang.String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
field public static final java.lang.String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
field public static final java.lang.String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index c6834f940554..32a8088e9c4e 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -922,6 +922,8 @@ public final class Pm {
flags |= UserInfo.FLAG_EPHEMERAL;
} else if ("--guest".equals(opt)) {
flags |= UserInfo.FLAG_GUEST;
+ } else if ("--demo".equals(opt)) {
+ flags |= UserInfo.FLAG_DEMO;
} else {
System.err.println("Error: unknown option " + opt);
return showUsage();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index eaea98958e45..05f49c5a1f02 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -39,6 +39,7 @@ import android.media.AudioManager;
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.BadParcelableException;
+import android.os.BaseBundle;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
@@ -53,6 +54,7 @@ import android.text.style.AbsoluteSizeSpan;
import android.text.style.CharacterStyle;
import android.text.style.RelativeSizeSpan;
import android.text.style.TextAppearanceSpan;
+import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import android.view.Gravity;
@@ -63,6 +65,7 @@ import android.widget.ProgressBar;
import android.widget.RemoteViews;
import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.NotificationColorUtil;
import java.lang.annotation.Retention;
@@ -70,6 +73,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -758,6 +762,16 @@ public class Notification implements Parcelable
public Bundle extras = new Bundle();
/**
+ * All pending intents in the notification extras (notification extras, actions extras,
+ * and remote input extras) as the system needs to be able to access them but touching
+ * the extras bundle in the system process is not safe because the bundle may contain
+ * custom parcelable objects.
+ *
+ * @hide
+ */
+ public ArraySet<PendingIntent> extrasPendingIntents;
+
+ /**
* {@link #extras} key: this is the title of the notification,
* as supplied to {@link Builder#setContentTitle(CharSequence)}.
*/
@@ -1573,7 +1587,16 @@ public class Notification implements Parcelable
/**
* Unflatten the notification from a parcel.
*/
- public Notification(Parcel parcel)
+ @SuppressWarnings("unchecked")
+ public Notification(Parcel parcel) {
+ // IMPORTANT: Add unmarshaling code in readFromParcel as the pending
+ // intents in extras are always written as the last entry.
+ readFromParcelImpl(parcel);
+ // Must be read last!
+ extrasPendingIntents = (ArraySet<PendingIntent>) parcel.readArraySet(null);
+ }
+
+ private void readFromParcelImpl(Parcel parcel)
{
int version = parcel.readInt();
@@ -1728,6 +1751,10 @@ public class Notification implements Parcelable
}
}
+ if (!ArrayUtils.isEmpty(extrasPendingIntents)) {
+ that.extrasPendingIntents = new ArraySet<>(extrasPendingIntents);
+ }
+
if (this.actions != null) {
that.actions = new Action[this.actions.length];
for(int i=0; i<this.actions.length; i++) {
@@ -1843,8 +1870,40 @@ public class Notification implements Parcelable
/**
* Flatten this notification into a parcel.
*/
- public void writeToParcel(Parcel parcel, int flags)
- {
+ public void writeToParcel(Parcel parcel, int flags) {
+ // We need to mark all pending intents getting into the notification
+ // system as being put there to later allow the notification ranker
+ // to launch them and by doing so add the app to the battery saver white
+ // list for a short period of time. The problem is that the system
+ // cannot look into the extras as there may be parcelables there that
+ // the platform does not know how to handle. To go around that we have
+ // an explicit list of the pending intents in the extras bundle.
+ final boolean collectPendingIntents = (extrasPendingIntents == null);
+ if (collectPendingIntents) {
+ PendingIntent.setOnMarshaledListener(
+ (PendingIntent intent, Parcel out, int outFlags) -> {
+ if (parcel == out) {
+ if (extrasPendingIntents == null) {
+ extrasPendingIntents = new ArraySet<>();
+ }
+ extrasPendingIntents.add(intent);
+ }
+ });
+ }
+ try {
+ // IMPORTANT: Add marshaling code in writeToParcelImpl as we
+ // want to intercept all pending events written to the pacel.
+ writeToParcelImpl(parcel, flags);
+ // Must be written last!
+ parcel.writeArraySet(extrasPendingIntents);
+ } finally {
+ if (collectPendingIntents) {
+ PendingIntent.setOnMarshaledListener(null);
+ }
+ }
+ }
+
+ private void writeToParcelImpl(Parcel parcel, int flags) {
parcel.writeInt(1);
parcel.writeLong(when);
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index cb15392b6a8a..cfa242be02aa 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -242,6 +242,36 @@ public final class PendingIntent implements Parcelable {
}
/**
+ * Listener for observing when pending intents are written to a parcel.
+ *
+ * @hide
+ */
+ public interface OnMarshaledListener {
+ /**
+ * Called when a pending intent is written to a parcel.
+ *
+ * @param intent The pending intent.
+ * @param parcel The parcel to which it was written.
+ * @param flags The parcel flags when it was written.
+ */
+ void onMarshaled(PendingIntent intent, Parcel parcel, int flags);
+ }
+
+ private static final ThreadLocal<OnMarshaledListener> sOnMarshaledListener
+ = new ThreadLocal<>();
+
+ /**
+ * Registers an listener for pending intents being written to a parcel.
+ *
+ * @param listener The listener, null to clear.
+ *
+ * @hide
+ */
+ public static void setOnMarshaledListener(OnMarshaledListener listener) {
+ sOnMarshaledListener.set(listener);
+ }
+
+ /**
* Retrieve a PendingIntent that will start a new activity, like calling
* {@link Context#startActivity(Intent) Context.startActivity(Intent)}.
* Note that the activity will be started outside of the context of an
@@ -1016,6 +1046,11 @@ public final class PendingIntent implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeStrongBinder(mTarget.asBinder());
+ OnMarshaledListener listener = sOnMarshaledListener.get();
+ if (listener != null) {
+ listener.onMarshaled(this, out, flags);
+ }
+
}
public static final Parcelable.Creator<PendingIntent> CREATOR
diff --git a/core/java/android/content/pm/IOtaDexopt.aidl b/core/java/android/content/pm/IOtaDexopt.aidl
index 786a77f64110..467bd5f5e82b 100644
--- a/core/java/android/content/pm/IOtaDexopt.aidl
+++ b/core/java/android/content/pm/IOtaDexopt.aidl
@@ -50,6 +50,13 @@ interface IOtaDexopt {
/**
* Optimize the next package. Note: this command is synchronous, that is, only returns after
* the package has been dexopted (or dexopting failed).
+ *
+ * Note: this will be removed after a transition period. Use nextDexoptCommand instead.
*/
void dexoptNextPackage();
+
+ /**
+ * Get the optimization parameters for the next package.
+ */
+ String nextDexoptCommand();
}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 26312475297c..74dcc0787b3b 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -17,8 +17,10 @@
package android.os;
import android.annotation.IntegerRes;
+import android.annotation.Nullable;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Size;
import android.util.SizeF;
@@ -734,6 +736,21 @@ public final class Parcel {
}
/**
+ * Write an array set to the parcel.
+ *
+ * @param val The array set to write.
+ *
+ * @hide
+ */
+ public void writeArraySet(@Nullable ArraySet<? extends Object> val) {
+ final int size = (val != null) ? val.size() : -1;
+ writeInt(size);
+ for (int i = 0; i < size; i++) {
+ writeValue(val.valueAt(i));
+ }
+ }
+
+ /**
* Flatten a Bundle into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
@@ -2735,6 +2752,26 @@ public final class Parcel {
readArrayMapInternal(outVal, N, loader);
}
+ /**
+ * Reads an array set.
+ *
+ * @param loader The class loader to use.
+ *
+ * @hide
+ */
+ public @Nullable ArraySet<? extends Object> readArraySet(ClassLoader loader) {
+ final int size = readInt();
+ if (size < 0) {
+ return null;
+ }
+ ArraySet<Object> result = new ArraySet<>(size);
+ for (int i = 0; i < size; i++) {
+ Object value = readValue(loader);
+ result.append(value);
+ }
+ return result;
+ }
+
private void readListInternal(List outVal, int N,
ClassLoader loader) {
while (N > 0) {
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 9e9314fba4c4..d39e91fd98b2 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -390,6 +390,32 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
}
/**
+ * Special fast path for appending items to the end of the array without validation.
+ * The array must already be large enough to contain the item.
+ * @hide
+ */
+ public void append(E value) {
+ final int index = mSize;
+ final int hash = value == null ? 0
+ : (mIdentityHashCode ? System.identityHashCode(value) : value.hashCode());
+ if (index >= mHashes.length) {
+ throw new IllegalStateException("Array is full");
+ }
+ if (index > 0 && mHashes[index - 1] > hash) {
+ RuntimeException e = new RuntimeException("here");
+ e.fillInStackTrace();
+ Log.w(TAG, "New hash " + hash
+ + " is before end of array hash " + mHashes[index - 1]
+ + " at index " + index, e);
+ add(value);
+ return;
+ }
+ mSize = index + 1;
+ mHashes[index] = hash;
+ mArray[index] = value;
+ }
+
+ /**
* Perform a {@link #add(Object)} of all values in <var>array</var>
* @param array The array whose contents are to be retrieved.
*/
diff --git a/libs/hwui/LayerUpdateQueue.cpp b/libs/hwui/LayerUpdateQueue.cpp
index db5f676d09dc..95f5cfb33474 100644
--- a/libs/hwui/LayerUpdateQueue.cpp
+++ b/libs/hwui/LayerUpdateQueue.cpp
@@ -26,6 +26,7 @@ void LayerUpdateQueue::clear() {
}
void LayerUpdateQueue::enqueueLayerWithDamage(RenderNode* renderNode, Rect damage) {
+ damage.roundOut();
damage.doIntersect(0, 0, renderNode->getWidth(), renderNode->getHeight());
if (!damage.isEmpty()) {
for (Entry& entry : mEntries) {
diff --git a/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp b/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp
index 8b0e91c77396..4db1cb935902 100644
--- a/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp
+++ b/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp
@@ -39,17 +39,21 @@ static sp<RenderNode> createSyncedNode(uint32_t width, uint32_t height) {
TEST(LayerUpdateQueue, enqueueSimple) {
sp<RenderNode> a = createSyncedNode(100, 100);
sp<RenderNode> b = createSyncedNode(200, 200);
+ sp<RenderNode> c = createSyncedNode(200, 200);
LayerUpdateQueue queue;
queue.enqueueLayerWithDamage(a.get(), Rect(25, 25, 75, 75));
queue.enqueueLayerWithDamage(b.get(), Rect(100, 100, 300, 300));
+ queue.enqueueLayerWithDamage(c.get(), Rect(.5, .5, .5, .5));
- EXPECT_EQ(2u, queue.entries().size());
+ EXPECT_EQ(3u, queue.entries().size());
EXPECT_EQ(a.get(), queue.entries()[0].renderNode);
EXPECT_EQ(Rect(25, 25, 75, 75), queue.entries()[0].damage);
EXPECT_EQ(b.get(), queue.entries()[1].renderNode);
EXPECT_EQ(Rect(100, 100, 200, 200), queue.entries()[1].damage); // clipped to bounds
+ EXPECT_EQ(c.get(), queue.entries()[2].renderNode);
+ EXPECT_EQ(Rect(0, 0, 1, 1), queue.entries()[2].damage); // rounded out
}
TEST(LayerUpdateQueue, enqueueUnion) {
diff --git a/packages/MtpDocumentsProvider/res/values-af/strings.xml b/packages/MtpDocumentsProvider/res/values-af/strings.xml
new file mode 100644
index 000000000000..c2c8761146f3
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-af/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP-gasheer"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Aflaaie"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Toegang tot lêers word tans van <xliff:g id="DEVICE_MODEL">%1$s</xliff:g> af verkry"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Die ander toestel is besig. Jy kan nie lêers oordra voordat dit beskikbaar is nie."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Geen lêers is gevind nie. Die ander toestel is dalk gesluit. Indien wel, ontsluit dit en probeer weer."</string>
+</resources>
diff --git a/packages/MtpDocumentsProvider/res/values-sv/strings.xml b/packages/MtpDocumentsProvider/res/values-sv/strings.xml
new file mode 100644
index 000000000000..26818eb220ce
--- /dev/null
+++ b/packages/MtpDocumentsProvider/res/values-sv/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="6271216747302322594">"MTP-värd"</string>
+ <string name="downloads_app_label" msgid="7120690641874849726">"Nedladdningar"</string>
+ <string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"Åtkomst till filer från <xliff:g id="DEVICE_MODEL">%1$s</xliff:g>"</string>
+ <string name="error_busy_device" msgid="3997316850357386589">"Den andra enheten är upptagen. Du kan inte överföra filer förrän den är tillgänglig."</string>
+ <string name="error_locked_device" msgid="7557872102188356147">"Inga filer hittades. Den andra enheten kan vara låst. Om den är det låser du upp den och försöker igen."</string>
+</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index d3f5d2667ebf..569a567c25fa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -82,8 +82,11 @@ public class CustomTile extends QSTile<QSTile.State> implements TileChangeListen
private void setTileIcon() {
try {
PackageManager pm = mContext.getPackageManager();
- ServiceInfo info = pm.getServiceInfo(mComponent,
- PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+ int flags = PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+ if (isSystemApp(pm)) {
+ flags |= PackageManager.MATCH_DISABLED_COMPONENTS;
+ }
+ ServiceInfo info = pm.getServiceInfo(mComponent, flags);
int icon = info.icon != 0 ? info.icon
: info.applicationInfo.icon;
// Update the icon if its not set or is the default icon.
@@ -103,6 +106,10 @@ public class CustomTile extends QSTile<QSTile.State> implements TileChangeListen
}
}
+ private boolean isSystemApp(PackageManager pm) throws PackageManager.NameNotFoundException {
+ return pm.getApplicationInfo(mComponent.getPackageName(), 0).isSystemApp();
+ }
+
/**
* Compare two icons, only works for resources.
*/
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 d5ff0b356d6d..42f398d8d83f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -153,7 +153,8 @@ public class KeyguardStatusBarView extends RelativeLayout
if (mKeyguardUserSwitcher == null) {
// If we have no keyguard switcher, the screen width is under 600dp. In this case,
// we don't show the multi-user avatar unless there is more than 1 user on the device.
- if (mUserSwitcherController.getSwitchableUserCount() > 1) {
+ if (mUserSwitcherController != null
+ && mUserSwitcherController.getSwitchableUserCount() > 1) {
mMultiUserSwitch.setVisibility(View.VISIBLE);
} else {
mMultiUserSwitch.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 5eaea90479ce..87e87c8e9bb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -154,8 +154,8 @@ public class StackScrollAlgorithm {
float newNotificationEnd = newYTranslation + newHeight;
boolean isHeadsUp = (child instanceof ExpandableNotificationRow)
&& ((ExpandableNotificationRow) child).isPinned();
- if (newYTranslation < previousNotificationEnd && ambientState.isShadeExpanded()
- && !isHeadsUp) {
+ if (newYTranslation < previousNotificationEnd
+ && (!isHeadsUp || ambientState.isShadeExpanded())) {
// The previous view is overlapping on top, clip!
float overlapAmount = previousNotificationEnd - newYTranslation;
state.clipTopAmount = (int) overlapAmount;
diff --git a/services/core/java/com/android/server/AttributeCache.java b/services/core/java/com/android/server/AttributeCache.java
index 57f18c086c56..58ec836547a7 100644
--- a/services/core/java/com/android/server/AttributeCache.java
+++ b/services/core/java/com/android/server/AttributeCache.java
@@ -25,23 +25,24 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.LruCache;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
-import java.lang.ref.WeakReference;
-
/**
* TODO: This should be better integrated into the system so it doesn't need
* special calls from the activity manager to clear it.
*/
public final class AttributeCache {
+ private static final int CACHE_SIZE = 4;
private static AttributeCache sInstance = null;
private final Context mContext;
@GuardedBy("this")
- private final ArrayMap<String, WeakReference<Package>> mPackages = new ArrayMap<>();
+ private final LruCache<String, Package> mPackages = new LruCache<>(CACHE_SIZE);
+
@GuardedBy("this")
private final Configuration mConfiguration = new Configuration();
@@ -86,15 +87,12 @@ public final class AttributeCache {
public void removePackage(String packageName) {
synchronized (this) {
- final WeakReference<Package> ref = mPackages.remove(packageName);
- final Package pkg = (ref != null) ? ref.get() : null;
+ final Package pkg = mPackages.remove(packageName);
if (pkg != null) {
- if (pkg.mMap != null) {
- for (int i = 0; i < pkg.mMap.size(); i++) {
- final ArrayMap<int[], Entry> map = pkg.mMap.valueAt(i);
- for (int j = 0; j < map.size(); j++) {
- map.valueAt(j).recycle();
- }
+ for (int i = 0; i < pkg.mMap.size(); i++) {
+ final ArrayMap<int[], Entry> map = pkg.mMap.valueAt(i);
+ for (int j = 0; j < map.size(); j++) {
+ map.valueAt(j).recycle();
}
}
@@ -113,15 +111,14 @@ public final class AttributeCache {
// The configurations being masked out are ones that commonly
// change so we don't want flushing the cache... all others
// will flush the cache.
- mPackages.clear();
+ mPackages.evictAll();
}
}
}
public Entry get(String packageName, int resId, int[] styleable, int userId) {
synchronized (this) {
- WeakReference<Package> ref = mPackages.get(packageName);
- Package pkg = (ref != null) ? ref.get() : null;
+ Package pkg = mPackages.get(packageName);
ArrayMap<int[], Entry> map = null;
Entry ent = null;
if (pkg != null) {
@@ -144,7 +141,7 @@ public final class AttributeCache {
return null;
}
pkg = new Package(context);
- mPackages.put(packageName, new WeakReference<>(pkg));
+ mPackages.put(packageName, pkg);
}
if (map == null) {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index baa0bbe3e4fb..8c5887f7a514 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -61,7 +61,7 @@ import java.util.Map;
class BluetoothManagerService extends IBluetoothManager.Stub {
private static final String TAG = "BluetoothManagerService";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
@@ -1512,7 +1512,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
BluetoothAdapter.STATE_TURNING_OFF);
- waitForOnOff(false, true);
+ boolean didDisableTimeout = !waitForOnOff(false, true);
bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
BluetoothAdapter.STATE_OFF);
@@ -1530,7 +1530,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mBluetoothLock.writeLock().unlock();
}
- SystemClock.sleep(100);
+ //
+ // If disabling Bluetooth times out, wait for an
+ // additional amount of time to ensure the process is
+ // shut down completely before attempting to restart.
+ //
+ if (didDisableTimeout) {
+ SystemClock.sleep(3000);
+ } else {
+ SystemClock.sleep(100);
+ }
mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
mState = BluetoothAdapter.STATE_OFF;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 798662910cbf..d9148817881b 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -43,7 +43,6 @@ import android.os.TransactionTooLargeException;
import android.util.ArrayMap;
import android.util.ArraySet;
-import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.app.procstats.ServiceState;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.TransferPipe;
@@ -751,6 +750,17 @@ public final class ActiveServices {
mAm.updateProcessForegroundLocked(proc, anyForeground, oomAdj);
}
+ private void updateWhitelistManagerLocked(ProcessRecord proc) {
+ proc.whitelistManager = false;
+ for (int i=proc.services.size()-1; i>=0; i--) {
+ ServiceRecord sr = proc.services.valueAt(i);
+ if (sr.whitelistManager) {
+ proc.whitelistManager = true;
+ break;
+ }
+ }
+ }
+
public void updateServiceConnectionActivitiesLocked(ProcessRecord clientProc) {
ArraySet<ProcessRecord> updatedProcesses = null;
for (int i = 0; i < clientProc.connections.size(); i++) {
@@ -997,6 +1007,9 @@ public final class ActiveServices {
if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
b.client.hasAboveClient = true;
}
+ if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
+ s.whitelistManager = true;
+ }
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
@@ -1019,6 +1032,9 @@ public final class ActiveServices {
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
s.app.treatLikeActivity = true;
}
+ if (s.whitelistManager) {
+ s.app.whitelistManager = true;
+ }
// This could have made the service more important.
mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
|| s.app.treatLikeActivity, b.client);
@@ -1807,6 +1823,10 @@ public final class ActiveServices {
}
}
+ if (r.whitelistManager) {
+ app.whitelistManager = true;
+ }
+
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
@@ -2018,6 +2038,9 @@ public final class ActiveServices {
r.stats.stopLaunchedLocked();
}
r.app.services.remove(r);
+ if (r.whitelistManager) {
+ updateWhitelistManagerLocked(r.app);
+ }
if (r.app.thread != null) {
updateServiceForegroundLocked(r.app, false);
try {
@@ -2085,6 +2108,14 @@ public final class ActiveServices {
if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
b.client.updateHasAboveClientLocked();
}
+ // If this connection requested whitelist management, see if we should
+ // now clear that state.
+ if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
+ s.updateWhitelistManager();
+ if (!s.whitelistManager && s.app != null) {
+ updateWhitelistManagerLocked(s.app);
+ }
+ }
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
@@ -2284,6 +2315,9 @@ public final class ActiveServices {
if (finishing) {
if (r.app != null && !r.app.persistent) {
r.app.services.remove(r);
+ if (r.whitelistManager) {
+ updateWhitelistManagerLocked(r.app);
+ }
}
r.app = null;
}
@@ -2379,6 +2413,9 @@ public final class ActiveServices {
service.app.removed = killProcess;
if (!service.app.persistent) {
service.app.services.remove(service);
+ if (service.whitelistManager) {
+ updateWhitelistManagerLocked(service.app);
+ }
}
}
service.app = null;
@@ -2497,6 +2534,8 @@ public final class ActiveServices {
updateServiceConnectionActivitiesLocked(app);
app.connections.clear();
+ app.whitelistManager = false;
+
// Clear app state from services.
for (int i = app.services.size() - 1; i >= 0; i--) {
ServiceRecord sr = app.services.valueAt(i);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 02d6a42dc5d5..5893f9018631 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19294,7 +19294,6 @@ public final class ActivityManagerService extends ActivityManagerNative
}
boolean mayBeTop = false;
- app.whitelistManager = false;
for (int is = app.services.size()-1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
@@ -19353,9 +19352,6 @@ public final class ActivityManagerService extends ActivityManagerNative
// Binding to ourself is not interesting.
continue;
}
- if ((cr.flags & Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
- app.whitelistManager = true;
- }
if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
ProcessRecord client = cr.binding.client;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 8fb10fdc1ea5..6d229466ebf9 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1706,7 +1706,8 @@ final class ActivityStack {
final boolean stackInvisible = stackVisibility != STACK_VISIBLE;
final boolean stackVisibleBehind = stackVisibility == STACK_VISIBLE_ACTIVITY_BEHIND;
boolean behindFullscreenActivity = stackInvisible;
- boolean resumeNextActivity = isFocusable() && (isInStackLocked(starting) == null);
+ boolean resumeNextActivity = mStackSupervisor.isFocusedStack(this)
+ && (isInStackLocked(starting) == null);
boolean behindTranslucentActivity = false;
final ActivityRecord visibleBehind = getVisibleBehindActivity();
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 0a081e9809ea..2bfc4021f887 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -90,6 +90,7 @@ final class ServiceRecord extends Binder {
ProcessRecord isolatedProc; // keep track of isolated process, if requested
ServiceState tracker; // tracking service execution, may be null
ServiceState restartTracker; // tracking service restart
+ boolean whitelistManager; // any bindings to this service have BIND_ALLOW_WHITELIST_MANAGEMENT?
boolean delayed; // are we waiting to start this service in the background?
boolean isForeground; // is service currently in foreground mode?
int foregroundId; // Notification ID of last foreground req.
@@ -225,6 +226,9 @@ final class ServiceRecord extends Binder {
if (isolatedProc != null) {
pw.print(prefix); pw.print("isolatedProc="); pw.println(isolatedProc);
}
+ if (whitelistManager) {
+ pw.print(prefix); pw.print("whitelistManager="); pw.println(whitelistManager);
+ }
if (delayed) {
pw.print(prefix); pw.print("delayed="); pw.println(delayed);
}
@@ -391,6 +395,19 @@ final class ServiceRecord extends Binder {
return false;
}
+ public void updateWhitelistManager() {
+ whitelistManager = false;
+ for (int conni=connections.size()-1; conni>=0; conni--) {
+ ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
+ for (int i=0; i<cr.size(); i++) {
+ if ((cr.get(i).flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
+ whitelistManager = true;
+ return;
+ }
+ }
+ }
+ }
+
public void resetRestartCounter() {
restartCount = 0;
restartDelay = 0;
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
index 9dce070221bc..a42d0cd4c831 100644
--- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
@@ -22,6 +22,7 @@ import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
+import android.util.Slog;
import android.util.TimeUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -40,6 +41,7 @@ import java.util.List;
*/
public class ContentObserverController extends StateController {
private static final String TAG = "JobScheduler.Content";
+ private static final boolean DEBUG = false;
/**
* Maximum number of changing URIs we will batch together to report.
@@ -88,6 +90,9 @@ public class ContentObserverController extends StateController {
if (taskStatus.contentObserverJobInstance == null) {
taskStatus.contentObserverJobInstance = new JobInstance(taskStatus);
}
+ if (DEBUG) {
+ Slog.i(TAG, "Tracking content-trigger job " + taskStatus);
+ }
mTrackedTasks.add(taskStatus);
boolean havePendingUris = false;
// If there is a previous job associated with the new job, propagate over
@@ -175,6 +180,9 @@ public class ContentObserverController extends StateController {
taskStatus.contentObserverJobInstance = null;
}
}
+ if (DEBUG) {
+ Slog.i(TAG, "No longer tracking job " + taskStatus);
+ }
mTrackedTasks.remove(taskStatus);
}
}
@@ -194,16 +202,20 @@ public class ContentObserverController extends StateController {
}
final class ObserverInstance extends ContentObserver {
- final Uri mUri;
+ final JobInfo.TriggerContentUri mUri;
final ArraySet<JobInstance> mJobs = new ArraySet<>();
- public ObserverInstance(Handler handler, Uri uri) {
+ public ObserverInstance(Handler handler, JobInfo.TriggerContentUri uri) {
super(handler);
mUri = uri;
}
@Override
public void onChange(boolean selfChange, Uri uri) {
+ if (DEBUG) {
+ Slog.i(TAG, "onChange(self=" + selfChange + ") for " + uri
+ + " when mUri=" + mUri);
+ }
synchronized (mLock) {
final int N = mJobs.size();
for (int i=0; i<N; i++) {
@@ -255,14 +267,25 @@ public class ContentObserverController extends StateController {
for (JobInfo.TriggerContentUri uri : uris) {
ObserverInstance obs = mObservers.get(uri);
if (obs == null) {
- obs = new ObserverInstance(mHandler, uri.getUri());
+ obs = new ObserverInstance(mHandler, uri);
mObservers.put(uri, obs);
+ final boolean andDescendants = (uri.getFlags() &
+ JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS) != 0;
+ if (DEBUG) {
+ Slog.v(TAG, "New observer " + obs + " for " + uri.getUri()
+ + " andDescendants=" + andDescendants);
+ }
mContext.getContentResolver().registerContentObserver(
uri.getUri(),
- (uri.getFlags() &
- JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)
- != 0,
+ andDescendants,
obs);
+ } else {
+ if (DEBUG) {
+ final boolean andDescendants = (uri.getFlags() &
+ JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS) != 0;
+ Slog.v(TAG, "Reusing existing observer " + obs + " for " + uri.getUri()
+ + " andDescendants=" + andDescendants);
+ }
}
obs.mJobs.add(this);
mMyObservers.add(obs);
@@ -315,8 +338,11 @@ public class ContentObserverController extends StateController {
final ObserverInstance obs = mMyObservers.get(i);
obs.mJobs.remove(this);
if (obs.mJobs.size() == 0) {
+ if (DEBUG) {
+ Slog.i(TAG, "Unregistering observer " + obs + " for " + obs.mUri.getUri());
+ }
mContext.getContentResolver().unregisterContentObserver(obs);
- mObservers.remove(obs);
+ mObservers.remove(obs.mUri);
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 59de263946a6..9209d3d4b54e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2598,7 +2598,6 @@ public class NotificationManagerService extends SystemService {
final long duration = LocalServices.getService(DeviceIdleController.LocalService.class)
.getNotificationWhitelistDuration();
- int size = 0;
if (notification.contentIntent != null) {
am.setPendingIntentWhitelistDuration(notification.contentIntent.getTarget(), duration);
}
@@ -2615,45 +2614,19 @@ public class NotificationManagerService extends SystemService {
continue;
}
am.setPendingIntentWhitelistDuration(action.actionIntent.getTarget(), duration);
- setPendingIntentWhitelistDuration(am, duration, action.getExtras());
- final RemoteInput[] remoteInputs = action.getRemoteInputs();
- if (remoteInputs != null) {
- for (RemoteInput remoteInput : remoteInputs) {
- setPendingIntentWhitelistDuration(am, duration, remoteInput.getExtras());
- }
- }
}
}
- }
-
- private static void setPendingIntentWhitelistDuration(ActivityManagerInternal am, long duration,
- Bundle extras) {
- for (String key : extras.keySet()) {
- final Object value = extras.get(key);
- if (value instanceof Parcelable) {
- setPendingIntentWhitelistDuration(am, duration, (Parcelable) value);
- } else if (value instanceof Parcelable[]) {
- for (Parcelable parcelable : (Parcelable[]) value) {
- setPendingIntentWhitelistDuration(am, duration, parcelable);
- }
- } else if (value instanceof List) {
- for (Object element : (List <?>) value) {
- if (element instanceof Parcelable) {
- setPendingIntentWhitelistDuration(am, duration, (Parcelable) element);
- }
+ if (notification.extrasPendingIntents != null) {
+ final int intentCount = notification.extrasPendingIntents.size();
+ for (int i = 0; i < intentCount; i++) {
+ PendingIntent pendingIntent = notification.extrasPendingIntents.valueAt(i);
+ if (pendingIntent != null) {
+ am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
}
}
}
}
- private static void setPendingIntentWhitelistDuration(ActivityManagerInternal am, long duration,
- Parcelable parcelable) {
- if (parcelable instanceof PendingIntent) {
- am.setPendingIntentWhitelistDuration(((PendingIntent) parcelable).getTarget(),
- duration);
- }
- }
-
private class EnqueueNotificationRunnable implements Runnable {
private final NotificationRecord r;
private final int userId;
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 7b85a4f25cee..72c549f7bec6 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -61,6 +61,13 @@ public final class Installer extends SystemService {
mInstaller = new InstallerConnection();
}
+ // Package-private installer that accepts a custom InstallerConnection. Used for
+ // OtaDexoptService.
+ Installer(Context context, InstallerConnection connection) {
+ super(context);
+ mInstaller = connection;
+ }
+
/**
* Yell loudly if someone tries making future calls while holding a lock on
* the given object.
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index df91f4a1f62a..01b3dc28b50e 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -32,10 +32,12 @@ import android.os.storage.StorageManager;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.os.InstallerConnection;
import com.android.internal.os.InstallerConnection.InstallerException;
import java.io.File;
import java.io.FileDescriptor;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -49,21 +51,28 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
private final static boolean DEBUG_DEXOPT = true;
private final Context mContext;
- private final PackageDexOptimizer mPackageDexOptimizer;
private final PackageManagerService mPackageManagerService;
// TODO: Evaluate the need for WeakReferences here.
+
+ /**
+ * The list of packages to dexopt.
+ */
private List<PackageParser.Package> mDexoptPackages;
+
+ /**
+ * The list of dexopt invocations for the current package (which will no longer be in
+ * mDexoptPackages). This can be more than one as a package may have multiple code paths,
+ * e.g., in the split-APK case.
+ */
+ private List<String> mCommandsForCurrentPackage;
+
private int completeSize;
public OtaDexoptService(Context context, PackageManagerService packageManagerService) {
this.mContext = context;
this.mPackageManagerService = packageManagerService;
- // Use the package manager install and install lock here for the OTA dex optimizer.
- mPackageDexOptimizer = new OTADexoptPackageDexOptimizer(packageManagerService.mInstaller,
- packageManagerService.mInstallLock, context);
-
// Now it's time to check whether we need to move any A/B artifacts.
moveAbArtifacts(packageManagerService.mInstaller);
}
@@ -93,6 +102,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
mPackageManagerService.mPackages.values(), mPackageManagerService);
}
completeSize = mDexoptPackages.size();
+ mCommandsForCurrentPackage = null;
}
@Override
@@ -101,6 +111,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
Log.i(TAG, "Cleaning up OTA Dexopt state.");
}
mDexoptPackages = null;
+ mCommandsForCurrentPackage = null;
}
@Override
@@ -109,15 +120,109 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
throw new IllegalStateException("done() called before prepare()");
}
- return mDexoptPackages.isEmpty();
+ return mDexoptPackages.isEmpty() && (mCommandsForCurrentPackage == null);
}
@Override
public synchronized float getProgress() throws RemoteException {
+ // We approximate by number of packages here. We could track all compiles, if we
+ // generated them ahead of time. Right now we're trying to conserve memory.
if (completeSize == 0) {
return 1f;
}
- return (completeSize - mDexoptPackages.size()) / ((float)completeSize);
+ int packagesLeft = mDexoptPackages.size() + (mCommandsForCurrentPackage != null ? 1 : 0);
+ return (completeSize - packagesLeft) / ((float)completeSize);
+ }
+
+ /**
+ * Return the next dexopt command for the current package. Enforces the invariant
+ */
+ private String getNextPackageDexopt() {
+ if (mCommandsForCurrentPackage != null) {
+ String next = mCommandsForCurrentPackage.remove(0);
+ if (mCommandsForCurrentPackage.isEmpty()) {
+ mCommandsForCurrentPackage = null;
+ }
+ return next;
+ }
+ return null;
+ }
+
+ @Override
+ public synchronized String nextDexoptCommand() throws RemoteException {
+ if (mDexoptPackages == null) {
+ throw new IllegalStateException("dexoptNextPackage() called before prepare()");
+ }
+
+ // Get the next command.
+ for (;;) {
+ // Check whether there's one for the current package.
+ String next = getNextPackageDexopt();
+ if (next != null) {
+ return next;
+ }
+
+ // Move to the next package, if possible.
+ if (mDexoptPackages.isEmpty()) {
+ return "Nothing to do";
+ }
+
+ PackageParser.Package nextPackage = mDexoptPackages.remove(0);
+
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Processing " + nextPackage.packageName + " for OTA dexopt.");
+ }
+
+ // Generate the next mPackageDexopts state. Ignore errors, this loop is strongly
+ // monotonically increasing, anyways.
+ generatePackageDexopts(nextPackage);
+
+ // Invariant check: mPackageDexopts is null or not empty.
+ if (mCommandsForCurrentPackage != null && mCommandsForCurrentPackage.isEmpty()) {
+ cleanup();
+ throw new IllegalStateException("mPackageDexopts empty for " + nextPackage);
+ }
+ }
+ }
+
+ /**
+ * Generate all dexopt commands for the given package and place them into mPackageDexopts.
+ * Returns true on success, false in an error situation like low disk space.
+ */
+ private synchronized boolean generatePackageDexopts(PackageParser.Package nextPackage) {
+ // Check for low space.
+ // TODO: If apps are not installed in the internal /data partition, we should compare
+ // against that storage's free capacity.
+ File dataDir = Environment.getDataDirectory();
+ @SuppressWarnings("deprecation")
+ long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
+ if (lowThreshold == 0) {
+ throw new IllegalStateException("Invalid low memory threshold");
+ }
+ long usableSpace = dataDir.getUsableSpace();
+ if (usableSpace < lowThreshold) {
+ Log.w(TAG, "Not running dexopt on " + nextPackage.packageName + " due to low memory: " +
+ usableSpace);
+ return false;
+ }
+
+ // Use our custom connection that just collects the commands.
+ RecordingInstallerConnection collectingConnection = new RecordingInstallerConnection();
+ Installer collectingInstaller = new Installer(mContext, collectingConnection);
+
+ // Use the package manager install and install lock here for the OTA dex optimizer.
+ PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
+ collectingInstaller, mPackageManagerService.mInstallLock, mContext);
+ optimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles,
+ null /* ISAs */, false /* checkProfiles */,
+ getCompilerFilterForReason(PackageManagerService.REASON_AB_OTA));
+
+ mCommandsForCurrentPackage = collectingConnection.commands;
+ if (mCommandsForCurrentPackage.isEmpty()) {
+ mCommandsForCurrentPackage = null;
+ }
+
+ return true;
}
@Override
@@ -152,8 +257,10 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
return;
}
- mPackageDexOptimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles,
- null /* ISAs */, false /* checkProfiles */,
+ PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
+ mPackageManagerService.mInstaller, mPackageManagerService.mInstallLock, mContext);
+ optimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles, null /* ISAs */,
+ false /* checkProfiles */,
getCompilerFilterForReason(PackageManagerService.REASON_AB_OTA));
}
@@ -218,4 +325,40 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
}
}
+
+ private static class RecordingInstallerConnection extends InstallerConnection {
+ public List<String> commands = new ArrayList<String>(1);
+
+ @Override
+ public void setWarnIfHeld(Object warnIfHeld) {
+ throw new IllegalStateException("Should not reach here");
+ }
+
+ @Override
+ public synchronized String transact(String cmd) {
+ commands.add(cmd);
+ return "0";
+ }
+
+ @Override
+ public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
+ throw new IllegalStateException("Should not reach here");
+ }
+
+ @Override
+ public boolean dumpProfiles(String gid, String packageName, String codePaths)
+ throws InstallerException {
+ throw new IllegalStateException("Should not reach here");
+ }
+
+ @Override
+ public void disconnect() {
+ throw new IllegalStateException("Should not reach here");
+ }
+
+ @Override
+ public void waitForConnection() {
+ throw new IllegalStateException("Should not reach here");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java b/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
index e8fdfa50a12d..bbd404879a21 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
@@ -46,6 +46,8 @@ class OtaDexoptShellCommand extends ShellCommand {
return runOtaDone();
case "step":
return runOtaStep();
+ case "next":
+ return runOtaNext();
case "progress":
return runOtaProgress();
default:
@@ -83,6 +85,11 @@ class OtaDexoptShellCommand extends ShellCommand {
return 0;
}
+ private int runOtaNext() throws RemoteException {
+ getOutPrintWriter().println(mInterface.nextDexoptCommand());
+ return 0;
+ }
+
private int runOtaProgress() throws RemoteException {
final float progress = mInterface.getProgress();
final PrintWriter pw = getOutPrintWriter();
@@ -103,6 +110,8 @@ class OtaDexoptShellCommand extends ShellCommand {
pw.println(" Replies whether the OTA is complete or not.");
pw.println(" step");
pw.println(" OTA dexopt the next package.");
+ pw.println(" next");
+ pw.println(" Get parameters for OTA dexopt of the next package.");
pw.println(" cleanup");
pw.println(" Clean up internal states. Ends an OTA session.");
}
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index 96e6da741a82..51b1e38237a1 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -55,6 +55,8 @@ import android.provider.Settings;
import android.util.Slog;
import com.android.internal.os.BackgroundThread;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
@@ -86,8 +88,12 @@ public class RetailDemoModeService extends SystemService {
AudioSystem.STREAM_MUSIC
};
+ // Tron Vars
+ private static final String DEMO_SESSION_COUNT = "retail_demo_session_count";
+ private static final String DEMO_SESSION_DURATION = "retail_demo_session_duration";
+
boolean mDeviceInDemoMode = false;
- int mCurrentUserId;
+ int mCurrentUserId = UserHandle.USER_SYSTEM;
private ActivityManagerService mAms;
private ActivityManagerInternal mAmi;
private AudioManager mAudioManager;
@@ -102,6 +108,15 @@ public class RetailDemoModeService extends SystemService {
private String[] mCameraIdsWithFlash;
private Configuration mPrimaryUserConfiguration;
+ final Object mActivityLock = new Object();
+ // Whether the newly created demo user has interacted with the screen yet
+ @GuardedBy("mActivityLock")
+ boolean mUserUntouched;
+ @GuardedBy("mActivityLock")
+ long mFirstUserActivityTime;
+ @GuardedBy("mActivityLock")
+ long mLastUserActivityTime;
+
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -136,18 +151,7 @@ public class RetailDemoModeService extends SystemService {
mWakeLock.acquire();
break;
case MSG_INACTIVITY_TIME_OUT:
- final IPackageManager pm = AppGlobals.getPackageManager();
- int enabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
- String demoLauncherComponent = getContext().getResources()
- .getString(R.string.config_demoModeLauncherComponent);
- try {
- enabledState = pm.getComponentEnabledSetting(
- ComponentName.unflattenFromString(demoLauncherComponent),
- mCurrentUserId);
- } catch (RemoteException exc) {
- Slog.e(TAG, "Unable to talk to Package Manager", exc);
- }
- if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
+ if (isDemoLauncherDisabled()) {
Slog.i(TAG, "User inactivity timeout reached");
showInactivityCountdownDialog();
}
@@ -158,6 +162,9 @@ public class RetailDemoModeService extends SystemService {
}
removeMessages(MSG_START_NEW_SESSION);
removeMessages(MSG_INACTIVITY_TIME_OUT);
+ if (mCurrentUserId != UserHandle.USER_SYSTEM) {
+ logSessionDuration();
+ }
final UserInfo demoUser = getUserManager().createUser(DEMO_USER_NAME,
UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL);
if (demoUser != null) {
@@ -190,6 +197,9 @@ public class RetailDemoModeService extends SystemService {
public RetailDemoModeService(Context context) {
super(context);
+ synchronized (mActivityLock) {
+ mFirstUserActivityTime = mLastUserActivityTime = SystemClock.uptimeMillis();
+ }
}
private Notification createResetNotification() {
@@ -213,6 +223,21 @@ public class RetailDemoModeService extends SystemService {
return mResetDemoPendingIntent;
}
+ boolean isDemoLauncherDisabled() {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ int enabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+ String demoLauncherComponent = getContext().getResources()
+ .getString(R.string.config_demoModeLauncherComponent);
+ try {
+ enabledState = pm.getComponentEnabledSetting(
+ ComponentName.unflattenFromString(demoLauncherComponent),
+ mCurrentUserId);
+ } catch (RemoteException exc) {
+ Slog.e(TAG, "Unable to talk to Package Manager", exc);
+ }
+ return enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+ }
+
private void setupDemoUser(UserInfo userInfo) {
UserManager um = getUserManager();
UserHandle user = UserHandle.of(userInfo.id);
@@ -226,6 +251,14 @@ public class RetailDemoModeService extends SystemService {
Settings.Secure.SKIP_FIRST_USE_HINTS, 1, userInfo.id);
}
+ void logSessionDuration() {
+ final int sessionDuration;
+ synchronized (mActivityLock) {
+ sessionDuration = (int) ((mLastUserActivityTime - mFirstUserActivityTime) / 1000);
+ }
+ MetricsLogger.count(getContext(), DEMO_SESSION_DURATION, sessionDuration);
+ }
+
private ActivityManagerService getActivityManager() {
if (mAms == null) {
mAms = (ActivityManagerService) ActivityManagerNative.getDefault();
@@ -395,11 +428,15 @@ public class RetailDemoModeService extends SystemService {
turnOffAllFlashLights();
muteVolumeStreams();
mAmi.updatePersistentConfigurationForUser(getPrimaryUsersConfiguration(), userId);
+ synchronized (mActivityLock) {
+ mUserUntouched = true;
+ }
+ MetricsLogger.count(getContext(), DEMO_SESSION_COUNT, 1);
+ mHandler.removeMessages(MSG_INACTIVITY_TIME_OUT);
}
private RetailDemoModeServiceInternal mLocalService = new RetailDemoModeServiceInternal() {
private static final long USER_ACTIVITY_DEBOUNCE_TIME = 2000;
- private long mLastUserActivityTime = 0;
@Override
public void onUserActivity() {
@@ -407,10 +444,17 @@ public class RetailDemoModeService extends SystemService {
return;
}
long timeOfActivity = SystemClock.uptimeMillis();
- if (timeOfActivity < mLastUserActivityTime + USER_ACTIVITY_DEBOUNCE_TIME) {
- return;
+ synchronized (mActivityLock) {
+ if (timeOfActivity < mLastUserActivityTime + USER_ACTIVITY_DEBOUNCE_TIME) {
+ return;
+ }
+ mLastUserActivityTime = timeOfActivity;
+ if (mUserUntouched && isDemoLauncherDisabled()) {
+ Slog.d(TAG, "retail_demo first touch");
+ mUserUntouched = false;
+ mFirstUserActivityTime = timeOfActivity;
+ }
}
- mLastUserActivityTime = timeOfActivity;
mHandler.removeMessages(MSG_INACTIVITY_TIME_OUT);
mHandler.sendEmptyMessageDelayed(MSG_INACTIVITY_TIME_OUT, USER_INACTIVITY_TIMEOUT);
}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 39302081b79a..2a0a9a640c6d 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -586,6 +586,8 @@ public abstract class Connection extends Conferenceable {
public void onExtrasChanged(Connection c, Bundle extras) {}
public void onExtrasRemoved(Connection c, List<String> keys) {}
public void onConnectionEvent(Connection c, String event, Bundle extras) {}
+ /** @hide */
+ public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {}
}
/**
@@ -2355,6 +2357,19 @@ public abstract class Connection extends Conferenceable {
}
/**
+ * Notifies listeners when a change has occurred to the Connection which impacts its ability to
+ * be a part of a conference call.
+ * @param isConferenceSupported {@code true} if the connection supports being part of a
+ * conference call, {@code false} otherwise.
+ * @hide
+ */
+ protected void notifyConferenceSupportedChanged(boolean isConferenceSupported) {
+ for (Listener l : mListeners) {
+ l.onConferenceSupportedChanged(this, isConferenceSupported);
+ }
+ }
+
+ /**
* Sends an event associated with this {@code Connection}, with associated event extras.
*
* Events are exposed to {@link InCallService} implementations via the
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 2458cc8c85ae..8399bb669da0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -808,6 +808,16 @@ public class CarrierConfigManager {
public static final String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL =
"drop_video_call_when_answering_audio_call_bool";
+ /**
+ * Flag indicating whether the carrier supports merging wifi calls when VoWIFI is disabled.
+ * This can happen in the case of a carrier which allows offloading video calls to WIFI
+ * separately of whether voice over wifi is enabled. In such a scenario when two video calls
+ * are downgraded to voice, they remain over wifi. However, if VoWIFI is disabled, these calls
+ * cannot be merged.
+ */
+ public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL =
+ "allow_merge_wifi_calls_when_vowifi_off_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -959,8 +969,9 @@ public class CarrierConfigManager {
// Order is important - lowest precidence first
sDefaults.putStringArray(KEY_RATCHET_RAT_FAMILIES,
new String[]{"1,2","7,8,12","3,11,9,10,15","14,19"});
- sDefaults.putBoolean(KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL, true);
- sDefaults.putBoolean(KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL, true);
+ sDefaults.putBoolean(KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL, false);
+ sDefaults.putBoolean(KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL, false);
+ sDefaults.putBoolean(KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL, true);
}
/**