Merge "Syncronize renderPage vs. onServiceDisconnected" into nyc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index f7b15ba..c631627 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -36768,9 +36768,11 @@
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
+ field public static final java.lang.String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
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 bf1842e..3fa518a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -39807,9 +39807,11 @@
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
+ field public static final java.lang.String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
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 fa06622..993f388 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -36846,9 +36846,11 @@
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
+ field public static final java.lang.String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
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 c6834f9..32a8088 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 @@
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 eaea989..05f49c5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -39,6 +39,7 @@
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.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.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.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 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 @@
/**
* 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 @@
}
}
+ 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 @@
/**
* 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 cb15392..cfa242b 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -242,6 +242,36 @@
}
/**
+ * 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 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 786a77f..467bd5f 100644
--- a/core/java/android/content/pm/IOtaDexopt.aidl
+++ b/core/java/android/content/pm/IOtaDexopt.aidl
@@ -50,6 +50,13 @@
/**
* 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 2631247..74dcc07 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 @@
}
/**
+ * 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 @@
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 9e9314f..d39e91f 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -390,6 +390,32 @@
}
/**
+ * 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/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index bddd826..36ab394 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -54,6 +54,7 @@
public class PlatLogoActivity extends Activity {
public static final boolean REVEAL_THE_NAME = false;
+ public static final boolean FINISH = false;
FrameLayout mLayout;
int mTapCount;
@@ -138,7 +139,7 @@
} catch (ActivityNotFoundException ex) {
Log.e("PlatLogoActivity", "No more eggs.");
}
- finish();
+ if (FINISH) finish();
}
});
return true;
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 4fc546c..b0028e1 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -573,8 +573,9 @@
bounds.roundOut();
}
+ incStrong(0);
auto functor = std::bind(
- std::mem_fn(&SurfaceViewPositionUpdater::doUpdatePosition), this,
+ std::mem_fn(&SurfaceViewPositionUpdater::doUpdatePositionAsync), this,
(jlong) info.canvasContext.getFrameNumber(),
(jint) bounds.left, (jint) bounds.top,
(jint) bounds.right, (jint) bounds.bottom);
@@ -585,15 +586,18 @@
virtual void onPositionLost(RenderNode& node, const TreeInfo* info) override {
if (CC_UNLIKELY(!mWeakRef || (info && !info->updateWindowPositions))) return;
- if (info) {
- auto functor = std::bind(
- std::mem_fn(&SurfaceViewPositionUpdater::doNotifyPositionLost), this,
- (jlong) info->canvasContext.getFrameNumber());
-
- info->canvasContext.enqueueFrameWork(std::move(functor));
- } else {
- doNotifyPositionLost(0);
+ ATRACE_NAME("SurfaceView position lost");
+ JNIEnv* env = jnienv();
+ jobject localref = env->NewLocalRef(mWeakRef);
+ if (CC_UNLIKELY(!localref)) {
+ jnienv()->DeleteWeakGlobalRef(mWeakRef);
+ mWeakRef = nullptr;
+ return;
}
+
+ env->CallVoidMethod(localref, gSurfaceViewPositionLostMethod,
+ info ? info->canvasContext.getFrameNumber() : 0);
+ env->DeleteLocalRef(localref);
}
private:
@@ -605,36 +609,23 @@
return env;
}
- void doUpdatePosition(jlong frameNumber, jint left, jint top,
+ void doUpdatePositionAsync(jlong frameNumber, jint left, jint top,
jint right, jint bottom) {
ATRACE_NAME("Update SurfaceView position");
JNIEnv* env = jnienv();
jobject localref = env->NewLocalRef(mWeakRef);
if (CC_UNLIKELY(!localref)) {
- jnienv()->DeleteWeakGlobalRef(mWeakRef);
+ env->DeleteWeakGlobalRef(mWeakRef);
mWeakRef = nullptr;
- return;
+ } else {
+ env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod,
+ frameNumber, left, top, right, bottom);
+ env->DeleteLocalRef(localref);
}
- env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod,
- frameNumber, left, top, right, bottom);
- env->DeleteLocalRef(localref);
- }
-
- void doNotifyPositionLost(jlong frameNumber) {
- ATRACE_NAME("SurfaceView position lost");
-
- JNIEnv* env = jnienv();
- jobject localref = env->NewLocalRef(mWeakRef);
- if (CC_UNLIKELY(!localref)) {
- jnienv()->DeleteWeakGlobalRef(mWeakRef);
- mWeakRef = nullptr;
- return;
- }
-
- env->CallVoidMethod(localref, gSurfaceViewPositionLostMethod, frameNumber);
- env->DeleteLocalRef(localref);
+ // We need to release ourselves here
+ decStrong(0);
}
JavaVM* mVm;
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index defa83a..516f252 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -19,10 +19,10 @@
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
- android:fillColor="#FF7E5BBF"
+ android:fillColor="#FFc7d4b6"
android:pathData="M32.0,12.5l0.0,28.0l12.0,-5.0l0.0,-28.0z"/>
<path
- android:fillColor="#FF7E5BBF"
+ android:fillColor="#FFfbd3cb"
android:pathData="M4.0,40.5l12.0,-5.0l0.0,-11.0l-12.0,-12.0z"/>
<path
android:fillColor="#40000000"
@@ -31,7 +31,7 @@
android:fillColor="#40000000"
android:pathData="M4.0,12.5l12.0,12.0l0.0,4.0z"/>
<path
- android:fillColor="#FF55C4F5"
+ android:fillColor="#FFe0e0d6"
android:pathData="M32.0,23.5l-16.0,-16.0l-12.0,5.0l0.0,0.0l12.0,12.0l16.0,16.0l12.0,-5.0l0.0,0.0z"/>
</vector>
diff --git a/libs/hwui/LayerUpdateQueue.cpp b/libs/hwui/LayerUpdateQueue.cpp
index db5f676..95f5cfb 100644
--- a/libs/hwui/LayerUpdateQueue.cpp
+++ b/libs/hwui/LayerUpdateQueue.cpp
@@ -26,6 +26,7 @@
}
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/RenderNode.h b/libs/hwui/RenderNode.h
index f80be5e..47fef6d 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -232,7 +232,7 @@
// the frameNumber to appropriately batch/synchronize these transactions.
// There is no other filtering/batching to ensure that only the "final"
// state called once per frame.
- class ANDROID_API PositionListener {
+ class ANDROID_API PositionListener : public VirtualLightRefBase {
public:
virtual ~PositionListener() {}
// Called when the RenderNode's position changes
@@ -247,7 +247,7 @@
// before the RenderNode is used for drawing.
// RenderNode takes ownership of the pointer
ANDROID_API void setPositionListener(PositionListener* listener) {
- mPositionListener.reset(listener);
+ mPositionListener = listener;
}
// This is only modified in MODE_FULL, so it can be safely accessed
@@ -366,7 +366,7 @@
// mDisplayList, not mStagingDisplayList.
uint32_t mParentCount;
- std::unique_ptr<PositionListener> mPositionListener;
+ sp<PositionListener> mPositionListener;
}; // class RenderNode
} /* namespace uirenderer */
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index d4956be..ceef9c7 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -784,6 +784,7 @@
}
sp<FuncTask> task(new FuncTask());
task->func = func;
+ mFrameFences.push_back(task);
mFrameWorkProcessor->add(task);
}
diff --git a/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp b/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp
index 8b0e91c..4db1cb9 100644
--- a/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp
+++ b/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp
@@ -39,17 +39,21 @@
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/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 71d1aaa..81ac594 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -297,8 +297,8 @@
Codec-specific data in the format is automatically submitted to the codec upon {@link #start};
you <strong>MUST NOT</strong> submit this data explicitly. If the format did not contain codec
specific data, you can choose to submit it using the specified number of buffers in the correct
- order, according to the format requirements. Alternately, you can concatenate all codec-specific
- data and submit it as a single codec-config buffer.
+ order, according to the format requirements. In case of H.264 AVC, you can also concatenate all
+ codec-specific data and submit it as a single codec-config buffer.
<p>
Android uses the following codec-specific data buffers. These are also required to be set in
the track format for proper {@link MediaMuxer} track configuration. Each parameter set and the
@@ -355,6 +355,13 @@
<td class=NA>Not Used</td>
<td class=NA>Not Used</td>
</tr>
+ <tr>
+ <td>VP9</td>
+ <td>VP9 <a href="http://wiki.webmproject.org/vp9-codecprivate">CodecPrivate</a> Data
+ (optional)</td>
+ <td class=NA>Not Used</td>
+ <td class=NA>Not Used</td>
+ </tr>
</tbody>
</table>
diff --git a/packages/EasterEgg/res/drawable/icon.xml b/packages/EasterEgg/res/drawable/icon.xml
index 5e08fcb..defa83a 100644
--- a/packages/EasterEgg/res/drawable/icon.xml
+++ b/packages/EasterEgg/res/drawable/icon.xml
@@ -14,15 +14,15 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
+ android:width="512dp"
+ android:height="512dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
- android:fillColor="#00796B"
+ android:fillColor="#FF7E5BBF"
android:pathData="M32.0,12.5l0.0,28.0l12.0,-5.0l0.0,-28.0z"/>
<path
- android:fillColor="#00796B"
+ android:fillColor="#FF7E5BBF"
android:pathData="M4.0,40.5l12.0,-5.0l0.0,-11.0l-12.0,-12.0z"/>
<path
android:fillColor="#40000000"
@@ -31,8 +31,7 @@
android:fillColor="#40000000"
android:pathData="M4.0,12.5l12.0,12.0l0.0,4.0z"/>
<path
- android:fillColor="#4DB6AC"
+ android:fillColor="#FF55C4F5"
android:pathData="M32.0,23.5l-16.0,-16.0l-12.0,5.0l0.0,0.0l12.0,12.0l16.0,16.0l12.0,-5.0l0.0,0.0z"/>
</vector>
-
diff --git a/packages/EasterEgg/src/com/android/egg/neko/Cat.java b/packages/EasterEgg/src/com/android/egg/neko/Cat.java
index 525b035..864b20c 100644
--- a/packages/EasterEgg/src/com/android/egg/neko/Cat.java
+++ b/packages/EasterEgg/src/com/android/egg/neko/Cat.java
@@ -16,7 +16,6 @@
import android.app.Notification;
import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -31,6 +30,8 @@
import com.android.egg.R;
public class Cat extends Drawable {
+ public static final long[] PURR = {0, 40, 20, 40, 20, 40, 20, 40, 20, 40, 20, 40};
+
private Random mNotSoRandom;
private Bitmap mBitmap;
private long mSeed;
@@ -198,6 +199,7 @@
.setContentText(getName())
.setContentIntent(PendingIntent.getActivity(context, 0, intent, 0))
.setAutoCancel(true)
+ .setVibrate(PURR)
.addExtras(extras);
}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
index 8fbab99..88a7968 100644
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
@@ -18,22 +18,35 @@
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.util.Log;
+import android.widget.Toast;
public class NekoActivationActivity extends Activity {
+ private void toastUp(String s) {
+ Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);
+ toast.getView().setBackgroundDrawable(null);
+ toast.show();
+ }
+
@Override
public void onStart() {
+ super.onStart();
+
final PackageManager pm = getPackageManager();
final ComponentName cn = new ComponentName(this, NekoTile.class);
if (pm.getComponentEnabledSetting(cn) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
if (NekoLand.DEBUG) {
Log.v("Neko", "Disabling tile.");
}
- pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
+ pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ toastUp("\uD83D\uDEAB");
} else {
if (NekoLand.DEBUG) {
Log.v("Neko", "Enabling tile.");
}
- pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+ pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP);
+ toastUp("\uD83D\uDC31");
}
finish();
}
diff --git a/packages/MtpDocumentsProvider/res/values-af/strings.xml b/packages/MtpDocumentsProvider/res/values-af/strings.xml
new file mode 100644
index 0000000..c2c8761
--- /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 0000000..26818eb
--- /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 d3f5d26..569a567 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 @@
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 @@
}
}
+ 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 d5ff0b35..42f398d 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 @@
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/services/core/java/com/android/server/AttributeCache.java b/services/core/java/com/android/server/AttributeCache.java
index 57f18c0..58ec836 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.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 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 @@
// 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 @@
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 baa0bbe..8c5887f 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -61,7 +61,7 @@
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 @@
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 @@
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 7986629..d914881 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.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 @@
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 @@
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 @@
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 @@
}
}
+ if (r.whitelistManager) {
+ app.whitelistManager = true;
+ }
+
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
@@ -2018,6 +2038,9 @@
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 @@
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 @@
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 @@
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 @@
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 02d6a42d..5893f90 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 @@
}
boolean mayBeTop = false;
- app.whitelistManager = false;
for (int is = app.services.size()-1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
@@ -19353,9 +19352,6 @@
// 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/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 0a081e9..2bfc402 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 @@
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 @@
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 @@
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/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 804be4e..c371f97 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -197,7 +197,7 @@
} else if (value instanceof Boolean) {
syncExtrasBundle.putBoolean(key, (Boolean) value);
} else if (value instanceof Float) {
- syncExtrasBundle.putDouble(key, (Double) value);
+ syncExtrasBundle.putDouble(key, (double) (float) value);
} else if (value instanceof Double) {
syncExtrasBundle.putDouble(key, (Double) value);
} else if (value instanceof String) {
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 9dce070..a42d0cd 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.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 @@
*/
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 @@
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 @@
taskStatus.contentObserverJobInstance = null;
}
}
+ if (DEBUG) {
+ Slog.i(TAG, "No longer tracking job " + taskStatus);
+ }
mTrackedTasks.remove(taskStatus);
}
}
@@ -194,16 +202,20 @@
}
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 @@
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 @@
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 59de263..9209d3d 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 @@
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 @@
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 7b85a4f..72c549f 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 @@
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 df91f4a1..01b3dc2 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.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 @@
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 @@
mPackageManagerService.mPackages.values(), mPackageManagerService);
}
completeSize = mDexoptPackages.size();
+ mCommandsForCurrentPackage = null;
}
@Override
@@ -101,6 +111,7 @@
Log.i(TAG, "Cleaning up OTA Dexopt state.");
}
mDexoptPackages = null;
+ mCommandsForCurrentPackage = null;
}
@Override
@@ -109,15 +120,109 @@
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 @@
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 @@
}
}
+
+ 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 e8fdfa5..bbd4048 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 @@
return runOtaDone();
case "step":
return runOtaStep();
+ case "next":
+ return runOtaNext();
case "progress":
return runOtaProgress();
default:
@@ -83,6 +85,11 @@
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 @@
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 96e6da74..51b1e38 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.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 @@
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 @@
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 @@
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 @@
}
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 RetailDemoModeService(Context context) {
super(context);
+ synchronized (mActivityLock) {
+ mFirstUserActivityTime = mLastUserActivityTime = SystemClock.uptimeMillis();
+ }
}
private Notification createResetNotification() {
@@ -213,6 +223,21 @@
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 @@
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 @@
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 @@
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 3930208..1b14d65 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -375,6 +375,14 @@
"android.telecom.extra.ANSWERING_DROPS_FG_CALL";
/**
+ * Boolean connection extra key on a {@link Connection} which indicates that adding an
+ * additional call is disallowed when there is a video call in progress.
+ * @hide
+ */
+ public static final String EXTRA_DISABLE_ADD_CALL_DURING_VIDEO_CALL =
+ "android.telecom.extra.DISABLE_ADD_CALL_DURING_VIDEO_CALL";
+
+ /**
* Connection event used to inform Telecom that it should play the on hold tone. This is used
* to play a tone when the peer puts the current call on hold. Sent to Telecom via
* {@link #sendConnectionEvent(String)}.
@@ -586,6 +594,8 @@
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 +2365,19 @@
}
/**
+ * 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 2458cc8..a5e50aa 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -808,6 +808,22 @@
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";
+
+ /**
+ * When true, indicates that adding a call is disabled when there is an ongoing video call.
+ */
+ public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL =
+ "allow_add_call_during_video_call";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -959,8 +975,10 @@
// 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);
+ sDefaults.putBoolean(KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL, true);
}
/**