Merge "Frameworks/base: Refactor Paint & Canvas native allocation support" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index f7a316d..d4f9d73 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -36419,6 +36419,7 @@
public class TelecomManager {
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method public void cancelMissedCallsNotification();
+ method public android.content.Intent createManageBlockedNumbersIntent();
method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
method public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
method public java.lang.String getDefaultDialerPackage();
diff --git a/api/system-current.txt b/api/system-current.txt
index b2b5982..db90b89 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -39118,6 +39118,7 @@
method public void cancelMissedCallsNotification();
method public deprecated void clearAccounts();
method public void clearPhoneAccounts();
+ method public android.content.Intent createManageBlockedNumbersIntent();
method public java.util.List<android.telecom.ParcelableCallAnalytics> dumpAnalytics();
method public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean);
method public boolean endCall();
diff --git a/api/test-current.txt b/api/test-current.txt
index 472daf6..ad3a5e6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -36434,6 +36434,7 @@
public class TelecomManager {
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method public void cancelMissedCallsNotification();
+ method public android.content.Intent createManageBlockedNumbersIntent();
method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
method public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
method public java.lang.String getDefaultDialerPackage();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0020a50..0d852e5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -75,6 +75,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
+import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.provider.Settings;
import android.security.NetworkSecurityPolicy;
@@ -3677,6 +3678,12 @@
ActivityManagerNative.getDefault().activityStopped(
activity.token, state, persistentState, description);
} catch (RemoteException ex) {
+ if (ex instanceof TransactionTooLargeException
+ && "com.google.android.gms".equals(activity.packageInfo.getPackageName())) {
+ Log.d(TAG, "STAHP SENDING SO MUCH DATA KTHX: " + ex);
+ return;
+ }
+
throw ex.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index ae433eb..06fe515 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -225,6 +225,10 @@
return mApplicationInfo;
}
+ public int getTargetSdkVersion() {
+ return mApplicationInfo.targetSdkVersion;
+ }
+
public boolean isSecurityViolation() {
return mSecurityViolation;
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index a9150e8..a54f40f 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -68,6 +68,7 @@
import java.io.IOException;
import java.io.InputStream;
+import java.util.Arrays;
import java.util.Locale;
/**
@@ -119,6 +120,9 @@
private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
sPreloadedComplexColors = new LongSparseArray<>();
+ /** Size of the cyclical cache used to map XML files to blocks. */
+ private static final int XML_BLOCK_CACHE_SIZE = 4;
+
// Pool of TypedArrays targeted to this Resources object.
final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
@@ -154,8 +158,9 @@
// Cyclical cache used for recently-accessed XML files.
private int mLastCachedXmlBlockIndex = -1;
- private final String[] mCachedXmlBlockFiles = new String[4];
- private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4];
+ private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE];
+ private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE];
+ private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE];
final AssetManager mAssets;
final ClassLoader mClassLoader;
@@ -2339,18 +2344,18 @@
* tools.
*/
public final void flushLayoutCache() {
- final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
- final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
- synchronized (cachedXmlBlockFiles) {
- final int num = cachedXmlBlockFiles.length;
- for (int i = 0; i < num; i++) {
+ synchronized (mCachedXmlBlocks) {
+ Arrays.fill(mCachedXmlBlockCookies, 0);
+ Arrays.fill(mCachedXmlBlockFiles, null);
+
+ final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+ for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) {
final XmlBlock oldBlock = cachedXmlBlocks[i];
if (oldBlock != null) {
oldBlock.close();
}
- cachedXmlBlockFiles[i] = null;
- cachedXmlBlocks[i] = null;
}
+ Arrays.fill(cachedXmlBlocks, null);
}
}
@@ -2852,13 +2857,14 @@
int assetCookie, @NonNull String type) throws NotFoundException {
if (id != 0) {
try {
- final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
- final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
- synchronized (cachedXmlBlockFiles) {
+ synchronized (mCachedXmlBlocks) {
+ final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies;
+ final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
+ final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
// First see if this block is in our cache.
final int num = cachedXmlBlockFiles.length;
for (int i = 0; i < num; i++) {
- if (cachedXmlBlockFiles[i] != null
+ if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null
&& cachedXmlBlockFiles[i].equals(file)) {
return cachedXmlBlocks[i].newParser();
}
@@ -2874,6 +2880,7 @@
if (oldBlock != null) {
oldBlock.close();
}
+ cachedXmlBlockCookies[pos] = assetCookie;
cachedXmlBlockFiles[pos] = file;
cachedXmlBlocks[pos] = block;
return block.newParser();
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index c72a6481..f48306a 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -69,7 +69,6 @@
* @return an array of requested float device temperatures.
* Empty if platform doesn't provide the queried temperature.
*
- * @throws IllegalArgumentException if an incorrect temperature type is queried.
* @throws SecurityException if a non profile or device owner tries to call this method.
*/
public @NonNull float[] getDeviceTemperatures(@DeviceTemperatureType int type) {
@@ -84,7 +83,8 @@
return new float[0];
}
default:
- throw new IllegalArgumentException();
+ Log.w(TAG, "Unknown device temperature type.");
+ return new float[0];
}
}
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 3796df7..9a4d69f 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1358,6 +1358,17 @@
+ Integer.toHexString(System.identityHashCode(this))
+ " isIconified=" + isIconified + "}";
}
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
}
@Override
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index ae109c6..abc6c4b 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -556,7 +556,7 @@
}
// For the rest of the function we will hold this lock, to serialize
- // looking/creation of Java proxies for native Binder proxies.
+ // looking/creation/destruction of Java proxies for native Binder proxies.
AutoMutex _l(mProxyLock);
// Someone else's... do we know about it?
@@ -1225,16 +1225,21 @@
static void android_os_BinderProxy_destroy(JNIEnv* env, jobject obj)
{
+ // Don't race with construction/initialization
+ AutoMutex _l(mProxyLock);
+
IBinder* b = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
DeathRecipientList* drl = (DeathRecipientList*)
env->GetLongField(obj, gBinderProxyOffsets.mOrgue);
LOGDEATH("Destroying BinderProxy %p: binder=%p drl=%p\n", obj, b, drl);
- env->SetLongField(obj, gBinderProxyOffsets.mObject, 0);
- env->SetLongField(obj, gBinderProxyOffsets.mOrgue, 0);
- drl->decStrong((void*)javaObjectForIBinder);
- b->decStrong((void*)javaObjectForIBinder);
+ if (b != nullptr) {
+ env->SetLongField(obj, gBinderProxyOffsets.mObject, 0);
+ env->SetLongField(obj, gBinderProxyOffsets.mOrgue, 0);
+ drl->decStrong((void*)javaObjectForIBinder);
+ b->decStrong((void*)javaObjectForIBinder);
+ }
IPCThreadState::self()->flushCommands();
}
diff --git a/packages/SystemUI/res/drawable/tv_pip_play_button.xml b/packages/SystemUI/res/drawable/tv_pip_play_button.xml
new file mode 100644
index 0000000..fecdc09
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_play_button.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:constantSize="true">
+ <item android:state_focused="true">
+ <layer-list>
+ <item android:drawable="@drawable/tv_pip_button_focused" />
+ <item android:drawable="@drawable/ic_play_arrow_white_24dp" />
+ </layer-list>
+ </item>
+ <item android:drawable="@drawable/ic_play_arrow_white_24dp" />
+</selector>
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
index 0b98d0e..1fec49e 100644
--- a/packages/SystemUI/res/layout/tv_pip_menu.xml
+++ b/packages/SystemUI/res/layout/tv_pip_menu.xml
@@ -34,7 +34,7 @@
android:gravity="center"
android:clipChildren="false">
- <ImageView android:id="@+id/full"
+ <ImageView android:id="@+id/full_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
@@ -53,17 +53,16 @@
android:clipChildren="false" />
</LinearLayout>
- <LinearLayout
+ <LinearLayout android:id="@+id/play_pause"
android:layout_width="34dp"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:layout_marginEnd="3dp"
android:orientation="vertical"
android:gravity="center"
- android:visibility="gone"
android:clipChildren="false">
- <ImageView android:id="@+id/play_pause"
+ <ImageView android:id="@+id/play_pause_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
@@ -90,7 +89,7 @@
android:gravity="center"
android:clipChildren="false">
- <ImageView android:id="@+id/close"
+ <ImageView android:id="@+id/close_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index c31bb33..c643d67 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -54,8 +54,7 @@
mQsContainer = container;
mQuickQsPanel = quickPanel;
mQsPanel = panel;
- mQuickQsPanel.addOnLayoutChangeListener(this);
- mQsPanel.addOnLayoutChangeListener(this);
+ container.addOnLayoutChangeListener(this);
QSTileLayout tileLayout = mQsPanel.getTileLayout();
if (tileLayout instanceof PagedTileLayout) {
((PagedTileLayout) tileLayout).setPageListener(this);
@@ -161,6 +160,7 @@
@Override
public void onAnimationAtStart() {
+ mQuickQsPanel.setVisibility(View.VISIBLE);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
index 026dd0e..35ade58 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
@@ -38,7 +38,7 @@
private final float mSpan;
private final Interpolator mInterpolator;
private final Listener mListener;
- private float mLastT;
+ private float mLastT = -1;
private TouchAnimator(Object[] targets, KeyframeSet[] keyframeSets,
float startDelay, float endDelay, Interpolator interpolator, Listener listener) {
@@ -56,15 +56,16 @@
if (mInterpolator != null) {
t = mInterpolator.getInterpolation(t);
}
+ if (t == mLastT) {
+ return;
+ }
if (mListener != null) {
- if (mLastT == 0 || mLastT == 1) {
- if (t != mLastT) {
- mListener.onAnimationStarted();
- }
- } else if (t == 1) {
+ if (t == 1) {
mListener.onAnimationAtEnd();
} else if (t == 0) {
mListener.onAnimationAtStart();
+ } else if (mLastT <= 0 || mLastT == 1) {
+ mListener.onAnimationStarted();
}
mLastT = t;
}
@@ -114,12 +115,12 @@
private Listener mListener;
public Builder addFloat(Object target, String property, float... values) {
- add(target, KeyframeSet.ofFloat(getProperty(target, property), values));
+ add(target, KeyframeSet.ofFloat(getProperty(target, property, float.class), values));
return this;
}
public Builder addInt(Object target, String property, int... values) {
- add(target, KeyframeSet.ofInt(getProperty(target, property), values));
+ add(target, KeyframeSet.ofInt(getProperty(target, property, int.class), values));
return this;
}
@@ -128,7 +129,7 @@
mValues.add(keyframeSet);
}
- private static Property getProperty(Object target, String property) {
+ private static Property getProperty(Object target, String property, Class<?> cls) {
if (target instanceof View) {
switch (property) {
case "translationX":
@@ -151,7 +152,7 @@
return View.SCALE_Y;
}
}
- return Property.of(target.getClass(), float.class, property);
+ return Property.of(target.getClass(), cls, property);
}
public Builder setStartDelay(float startDelay) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 67fe8e5e..225c10f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -77,11 +77,10 @@
TypedValue value = new TypedValue();
mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
mToolbar.setNavigationIcon(
- getResources().getDrawable(R.drawable.ic_close_white, mContext.getTheme()));
+ getResources().getDrawable(value.resourceId, mContext.getTheme()));
mToolbar.setNavigationOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- save();
hide((int) v.getX() + v.getWidth() / 2, (int) v.getY() + v.getHeight() / 2);
}
});
@@ -115,6 +114,7 @@
public void hide(int x, int y) {
if (isShown) {
isShown = false;
+ save();
mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index c6c497f..d1953b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -27,7 +27,6 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.systemui.R;
@@ -159,13 +158,6 @@
TileInfo info = mTiles.get(position);
holder.mTileView.onStateChanged(info.state);
- holder.mTileView.setOnTouchListener(new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- mItemTouchHelper.startDrag(holder);
- return true;
- }
- });
}
public SpanSizeLookup getSizeLookup() {
@@ -179,6 +171,7 @@
super(itemView);
if (itemView instanceof FrameLayout) {
mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
+ mTileView.setBackground(null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index e4e3790..12c8c44 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -69,6 +69,11 @@
}
@Override
+ public boolean isAvailable() {
+ return mFlashlightController.hasFlashlight();
+ }
+
+ @Override
protected void handleClick() {
if (ActivityManager.isUserAMonkey()) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 9450287..0c48cf7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -97,6 +97,9 @@
@Override
public void onPipResizeAboutToStart() { }
+
+ @Override
+ public void onMediaControllerChanged() { }
};
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index cf5531f..b549d59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -38,7 +38,6 @@
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QuickQSPanel;
import com.android.systemui.qs.TouchAnimator;
-import com.android.systemui.qs.TouchAnimator.Listener;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
@@ -46,7 +45,7 @@
import com.android.systemui.tuner.TunerService;
public class QuickStatusBarHeader extends BaseStatusBarHeader implements
- NextAlarmChangeCallback, OnClickListener, Listener {
+ NextAlarmChangeCallback, OnClickListener {
private static final String TAG = "QuickStatusBarHeader";
@@ -157,7 +156,6 @@
mAnimator = new TouchAnimator.Builder()
.addFloat(mSettingsContainer, "translationY", -mGearTranslation, 0)
.addFloat(mMultiUserSwitch, "translationY", -mGearTranslation, 0)
- .setListener(this)
.build();
mSecondHalfAnimator = new TouchAnimator.Builder()
.addFloat(mSettingsButton, "rotation", -180, 0)
@@ -224,20 +222,6 @@
mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD);
}
- @Override
- public void onAnimationAtStart() {
- }
-
- @Override
- public void onAnimationAtEnd() {
- mHeaderQsPanel.setVisibility(View.INVISIBLE);
- }
-
- @Override
- public void onAnimationStarted() {
- mHeaderQsPanel.setVisibility(View.VISIBLE);
- }
-
private void updateAlarmVisibilities() {
mAlarmStatus.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index 29a8f67..9a21a1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -93,6 +93,10 @@
}
}
+ public boolean hasFlashlight() {
+ return mCameraId != null;
+ }
+
public synchronized boolean isEnabled() {
return mFlashlightEnabled;
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 0925638..123165e 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -23,11 +23,14 @@
import android.app.IActivityManager;
import android.app.ITaskStackListener;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
import android.os.Debug;
import android.os.Handler;
import android.os.RemoteException;
@@ -69,6 +72,7 @@
private Context mContext;
private IActivityManager mActivityManager;
+ private MediaSessionManager mMediaSessionManager;
private int mState = STATE_NO_PIP;
private final Handler mHandler = new Handler();
private List<Listener> mListeners = new ArrayList<>();
@@ -79,6 +83,8 @@
private Rect mRecentsFocusedPipBounds;
private boolean mInitialized;
private int mPipTaskId = TASK_ID_NO_PIP;
+ private ComponentName mPipComponentName;
+ private MediaController mPipMediaController;
private boolean mOnboardingShown;
private boolean mIsRecentsShown;
@@ -100,10 +106,15 @@
}
if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo);
mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1];
+ mPipComponentName = ComponentName.unflattenFromString(
+ stackInfo.taskNames[stackInfo.taskNames.length - 1]);
// Set state to overlay so we show it when the pinned stack animation ends.
mState = STATE_PIP_OVERLAY;
mCurrentPipBounds = mPipBounds;
launchPipOnboardingActivityIfNeeded();
+ mMediaSessionManager.addOnActiveSessionsChangedListener(
+ mActiveMediaSessionListener, null);
+ updateMediaController(mMediaSessionManager.getActiveSessions(null));
}
};
private final Runnable mOnTaskStackChanged = new Runnable() {
@@ -176,6 +187,13 @@
}
};
+ private final MediaSessionManager.OnActiveSessionsChangedListener mActiveMediaSessionListener =
+ new MediaSessionManager.OnActiveSessionsChangedListener() {
+ @Override
+ public void onActiveSessionsChanged(List<MediaController> controllers) {
+ updateMediaController(controllers);
+ }
+ };
private PipManager() { }
@@ -215,6 +233,9 @@
mContext.registerReceiver(mBroadcastReceiver, intentFilter);
mOnboardingShown = Prefs.getBoolean(
mContext, TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN, false);
+
+ mMediaSessionManager =
+ (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
}
/**
@@ -248,6 +269,8 @@
private void closePipInternal(boolean removePipStack) {
mState = STATE_NO_PIP;
mPipTaskId = TASK_ID_NO_PIP;
+ mPipMediaController = null;
+ mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveMediaSessionListener);
if (removePipStack) {
try {
mActivityManager.removeStack(PINNED_STACK_ID);
@@ -502,6 +525,34 @@
}
}
+ private void updateMediaController(List<MediaController> controllers) {
+ MediaController mediaController = null;
+ if (controllers != null && mState != STATE_NO_PIP && mPipComponentName != null) {
+ for (int i = controllers.size() - 1; i >= 0; i--) {
+ MediaController controller = controllers.get(i);
+ // We assumes that an app with PIPable activity
+ // keeps the single instance of media controller especially when PIP is on.
+ if (controller.getPackageName().equals(mPipComponentName.getPackageName())) {
+ mediaController = controller;
+ break;
+ }
+ }
+ }
+ if (mPipMediaController != mediaController) {
+ mPipMediaController = mediaController;
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ mListeners.get(i).onMediaControllerChanged();
+ }
+ }
+ }
+
+ /**
+ * Gets the {@link android.media.session.MediaController} for the PIPed activity.
+ */
+ MediaController getMediaController() {
+ return mPipMediaController;
+ }
+
private class TaskStackListener extends ITaskStackListener.Stub {
@Override
public void onTaskStackChanged() throws RemoteException {
@@ -542,6 +593,8 @@
void onMoveToFullscreen();
/** Invoked when we are above to start resizing the Pip. */
void onPipResizeAboutToStart();
+ /** Invoked when the MediaController on PIPed activity is changed. */
+ void onMediaControllerChanged();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index a392bec..fb7fa4d 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -18,34 +18,49 @@
import android.app.Activity;
import android.media.session.MediaController;
+import android.media.session.PlaybackState;
import android.os.Bundle;
import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
import com.android.systemui.R;
+import static android.content.pm.PackageManager.FEATURE_LEANBACK;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+import static android.media.session.PlaybackState.ACTION_PAUSE;
+import static android.media.session.PlaybackState.ACTION_PLAY;
+
/**
* Activity to show the PIP menu to control PIP.
*/
public class PipMenuActivity extends Activity implements PipManager.Listener {
private static final String TAG = "PipMenuActivity";
- private static final boolean DEBUG = false;
private final PipManager mPipManager = PipManager.getInstance();
private MediaController mMediaController;
private View mFullButtonView;
private View mFullDescriptionView;
- private View mPlayPauseButtonView;
- private View mPlayPauseDescriptionView;
+ private View mPlayPauseView;
+ private ImageView mPlayPauseButtonImageView;
+ private TextView mPlayPauseDescriptionTextView;
private View mCloseButtonView;
private View mCloseDescriptionView;
+ private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
+ @Override
+ public void onPlaybackStateChanged(PlaybackState state) {
+ updatePlayPauseView(state);
+ }
+ };
+
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.tv_pip_menu);
mPipManager.addListener(this);
- mFullButtonView = findViewById(R.id.full);
+ mFullButtonView = findViewById(R.id.full_button);
mFullDescriptionView = findViewById(R.id.full_desc);
mFullButtonView.setOnClickListener(new View.OnClickListener() {
@Override
@@ -61,22 +76,33 @@
}
});
- mPlayPauseButtonView = findViewById(R.id.play_pause);
- mPlayPauseDescriptionView = findViewById(R.id.play_pause_desc);
- mPlayPauseButtonView.setOnClickListener(new View.OnClickListener() {
+ mPlayPauseView = findViewById(R.id.play_pause);
+ mPlayPauseButtonImageView = (ImageView) findViewById(R.id.play_pause_button);
+ mPlayPauseDescriptionTextView = (TextView) findViewById(R.id.play_pause_desc);
+ mPlayPauseButtonImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- // TODO: Implement play/pause.
+ if (mMediaController == null || mMediaController.getPlaybackState() == null) {
+ return;
+ }
+ long actions = mMediaController.getPlaybackState().getActions();
+ int state = mMediaController.getPlaybackState().getState();
+ if (((actions & ACTION_PLAY) != 0) && !isPlaying(state)) {
+ mMediaController.getTransportControls().play();
+ } else if ((actions & ACTION_PAUSE) != 0 && isPlaying(state)) {
+ mMediaController.getTransportControls().pause();
+ }
+ // View will be updated later in {@link mMediaControllerCallback}
}
});
- mPlayPauseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ mPlayPauseButtonImageView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
- mPlayPauseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+ mPlayPauseDescriptionTextView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
}
});
- mCloseButtonView = findViewById(R.id.close);
+ mCloseButtonView = findViewById(R.id.close_button);
mCloseDescriptionView = findViewById(R.id.close_desc);
mCloseButtonView.setOnClickListener(new View.OnClickListener() {
@Override
@@ -91,6 +117,50 @@
mCloseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
}
});
+ updateMediaController();
+ }
+
+ private void updateMediaController() {
+ MediaController newController = mPipManager.getMediaController();
+ if (mMediaController == newController) {
+ return;
+ }
+ if (mMediaController != null) {
+ mMediaController.unregisterCallback(mMediaControllerCallback);
+ }
+ mMediaController = newController;
+ if (mMediaController != null) {
+ mMediaController.registerCallback(mMediaControllerCallback);
+ updatePlayPauseView(mMediaController.getPlaybackState());
+ } else {
+ updatePlayPauseView(null);
+ }
+ }
+
+ private void updatePlayPauseView(PlaybackState playbackState) {
+ if (playbackState != null
+ && (playbackState.getActions() & (ACTION_PLAY | ACTION_PAUSE)) != 0) {
+ mPlayPauseView.setVisibility(View.VISIBLE);
+ if (isPlaying(playbackState.getState())) {
+ mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_pause_button);
+ mPlayPauseDescriptionTextView.setText(R.string.pip_pause);
+ } else {
+ mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_play_button);
+ mPlayPauseDescriptionTextView.setText(R.string.pip_play);
+ }
+ } else {
+ mPlayPauseView.setVisibility(View.GONE);
+ }
+ }
+
+ private boolean isPlaying(int state) {
+ return state == PlaybackState.STATE_BUFFERING
+ || state == PlaybackState.STATE_CONNECTING
+ || state == PlaybackState.STATE_PLAYING
+ || state == PlaybackState.STATE_FAST_FORWARDING
+ || state == PlaybackState.STATE_REWINDING
+ || state == PlaybackState.STATE_SKIPPING_TO_PREVIOUS
+ || state == PlaybackState.STATE_SKIPPING_TO_NEXT;
}
private void restorePipAndFinish() {
@@ -107,6 +177,9 @@
@Override
protected void onDestroy() {
super.onDestroy();
+ if (mMediaController != null) {
+ mMediaController.unregisterCallback(mMediaControllerCallback);
+ }
mPipManager.removeListener(this);
mPipManager.resumePipResizing(
PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
@@ -131,6 +204,11 @@
}
@Override
+ public void onMediaControllerChanged() {
+ updateMediaController();
+ }
+
+ @Override
public void onPipResizeAboutToStart() {
finish();
mPipManager.suspendPipResizing(
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
index e5c07d2..ad45625b 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
@@ -82,6 +82,8 @@
}
@Override
- public void onPipResizeAboutToStart() {
- }
+ public void onPipResizeAboutToStart() { }
+
+ @Override
+ public void onMediaControllerChanged() { }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index cfeab6d..95d655c 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -103,4 +103,8 @@
mPipManager.suspendPipResizing(
PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH);
}
+
+ @Override
+ public void onMediaControllerChanged() {
+ }
}
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 2825601..5389c804 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -20,6 +20,8 @@
<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
<application>
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
new file mode 100644
index 0000000..1d81fd4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTests.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.view.View;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.qs.TouchAnimator.Listener;
+import org.mockito.Mockito;
+
+public class TouchAnimatorTests extends SysuiTestCase {
+
+ private Listener mTouchListener;
+ private View mTestView;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mTestView = new View(getContext());
+ mTouchListener = Mockito.mock(Listener.class);
+ }
+
+ public void testSetValueFloat() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .addFloat(mTestView, "x", 0, 50)
+ .build();
+
+ animator.setPosition(0);
+ assertEquals(0f, mTestView.getX());
+
+ animator.setPosition(.5f);
+ assertEquals(25f, mTestView.getX());
+
+ animator.setPosition(1);
+ assertEquals(50f, mTestView.getX());
+ }
+
+ public void testSetValueInt() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .addInt(mTestView, "top", 0, 50)
+ .build();
+
+ animator.setPosition(0);
+ assertEquals(0, mTestView.getTop());
+
+ animator.setPosition(.5f);
+ assertEquals(25, mTestView.getTop());
+
+ animator.setPosition(1);
+ assertEquals(50, mTestView.getTop());
+ }
+
+ public void testStartDelay() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .addFloat(mTestView, "x", 0, 50)
+ .setStartDelay(.5f)
+ .build();
+
+ animator.setPosition(0);
+ assertEquals(0f, mTestView.getX());
+
+ animator.setPosition(.5f);
+ assertEquals(0f, mTestView.getX());
+
+ animator.setPosition(.75f);
+ assertEquals(25f, mTestView.getX());
+
+ animator.setPosition(1);
+ assertEquals(50f, mTestView.getX());
+ }
+
+ public void testEndDelay() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .addFloat(mTestView, "x", 0, 50)
+ .setEndDelay(.5f)
+ .build();
+
+ animator.setPosition(0);
+ assertEquals(0f, mTestView.getX());
+
+ animator.setPosition(.25f);
+ assertEquals(25f, mTestView.getX());
+
+ animator.setPosition(.5f);
+ assertEquals(50f, mTestView.getX());
+
+ animator.setPosition(1);
+ assertEquals(50f, mTestView.getX());
+ }
+
+ public void testOnAnimationAtStartCallback() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .setListener(mTouchListener)
+ .build();
+
+ // Called on init.
+ animator.setPosition(0);
+ verifyOnAnimationAtStart(1);
+
+ // Not called from same state.
+ animator.setPosition(0);
+ verifyOnAnimationAtStart(1);
+
+ // Called after starting and moving back to start.
+ animator.setPosition(.5f);
+ animator.setPosition(0);
+ verifyOnAnimationAtStart(2);
+
+ // Called when move from end to end.
+ animator.setPosition(1);
+ animator.setPosition(0);
+ verifyOnAnimationAtStart(3);
+ }
+
+ public void testOnAnimationAtEndCallback() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .setListener(mTouchListener)
+ .build();
+
+ // Called on init.
+ animator.setPosition(1);
+ verifyOnAnimationAtEnd(1);
+
+ // Not called from same state.
+ animator.setPosition(1);
+ verifyOnAnimationAtEnd(1);
+
+ // Called after starting and moving back to end.
+ animator.setPosition(.5f);
+ animator.setPosition(1);
+ verifyOnAnimationAtEnd(2);
+
+ // Called when move from end to end.
+ animator.setPosition(0);
+ animator.setPosition(1);
+ verifyOnAnimationAtEnd(3);
+ }
+
+ public void testOnAnimationStartedCallback() {
+ TouchAnimator animator = new TouchAnimator.Builder()
+ .setListener(mTouchListener)
+ .build();
+
+ // Called on init.
+ animator.setPosition(.5f);
+ verifyOnAnimationStarted(1);
+
+ // Not called from same state.
+ animator.setPosition(.6f);
+ verifyOnAnimationStarted(1);
+
+ // Called after going to end then moving again.
+ animator.setPosition(1);
+ animator.setPosition(.5f);
+ verifyOnAnimationStarted(2);
+
+ // Called after moving to start then moving again.
+ animator.setPosition(0);
+ animator.setPosition(.5f);
+ verifyOnAnimationStarted(3);
+ }
+
+ // TODO: Add test for interpolator.
+
+ private void verifyOnAnimationAtStart(int times) {
+ Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationAtStart();
+ }
+
+ private void verifyOnAnimationAtEnd(int times) {
+ Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationAtEnd();
+ }
+
+ private void verifyOnAnimationStarted(int times) {
+ Mockito.verify(mTouchListener, Mockito.times(times)).onAnimationStarted();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
index c4ca039..1841251 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
@@ -19,6 +19,9 @@
import android.os.Looper;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.NetworkController;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
@@ -34,7 +37,12 @@
protected void setUp() throws Exception {
super.setUp();
mManagers = new ArrayList<>();
- QSTileHost host = new QSTileHost(mContext, null, null, null, null, null, null, null, null,
+ final NetworkController networkController = Mockito.mock(NetworkController.class);
+ Mockito.when(networkController.getDataSaverController()).thenReturn(
+ Mockito.mock(DataSaverController.class));
+ QSTileHost host = new QSTileHost(mContext, null, null, null, null,
+ networkController, null,
+ Mockito.mock(HotspotController.class), null,
null, null, null, null, null, null, null);
mTileService = new TestTileServices(host, Looper.myLooper());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 5cf3767..ebd5384 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -16,9 +16,6 @@
package com.android.systemui.statusbar.policy;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
@@ -31,14 +28,12 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
-
import com.android.internal.telephony.cdma.EriInfo;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
-
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
@@ -47,6 +42,9 @@
import java.util.ArrayList;
import java.util.List;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
public class NetworkControllerBaseTest extends SysuiTestCase {
private static final String TAG = "NetworkControllerBaseTest";
protected static final int DEFAULT_LEVEL = 2;
@@ -109,6 +107,7 @@
protected void setupNetworkController() {
// For now just pretend to be the data sim, so we can test that too.
mSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+ when(mMockTm.getDataEnabled(mSubId)).thenReturn(true);
setDefaultSubId(mSubId);
setSubscriptions(mSubId);
mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
diff --git a/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java b/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
index 8786350..389e0a1 100644
--- a/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
+++ b/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
@@ -210,6 +210,9 @@
}
public void onPackageUninstalledLPw(PackageParser.Package pkg) {
+ if (pkg == null) {
+ return;
+ }
PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index aa0db99..9988694 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2449,33 +2449,6 @@
reconcileAppsData(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM,
storageFlags);
- if (!StorageManager.isFileBasedEncryptionEnabled()
- && PackageManager.APPLY_FORCE_DEVICE_ENCRYPTED) {
- // When upgrading a non-FBE device, we might need to shuffle
- // around the default storage location of system apps
- final List<UserInfo> users = sUserManager.getUsers(true);
- for (PackageSetting ps : mSettings.mPackages.values()) {
- if (ps.pkg == null || !ps.isSystem()) continue;
- final int storageTarget = ps.pkg.applicationInfo.isForceDeviceEncrypted()
- ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
- for (UserInfo user : users) {
- if (ps.getInstalled(user.id)) {
- try {
- mInstaller.migrateAppData(StorageManager.UUID_PRIVATE_INTERNAL,
- ps.name, user.id, storageTarget);
- } catch (InstallerException e) {
- logCriticalInfo(Log.WARN,
- "Failed to migrate " + ps.name + ": " + e.getMessage());
- }
- // We may have just shuffled around app data
- // directories, so prepare it one more time
- prepareAppData(StorageManager.UUID_PRIVATE_INTERNAL, user.id,
- storageFlags, ps.pkg, false);
- }
- }
- }
- }
-
// If this is first boot after an OTA, and a normal boot, then
// we need to clear code cache directories.
if (mIsUpgrade && !onlyCore) {
@@ -13330,18 +13303,21 @@
return null;
}
- private void removeNativeBinariesLI(PackageParser.Package pkg) {
+ private void removeNativeBinariesLI(PackageSetting ps) {
// Remove the lib path for the parent package
- PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps != null) {
NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
- }
- // Remove the lib path for the child packages
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- ps = (PackageSetting) pkg.childPackages.get(i).mExtras;
- if (ps != null) {
- NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
+ // Remove the lib path for the child packages
+ final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
+ for (int i = 0; i < childCount; i++) {
+ PackageSetting childPs = null;
+ synchronized (mPackages) {
+ childPs = mSettings.peekPackageLPr(ps.childPackageNames.get(i));
+ }
+ if (childPs != null) {
+ NativeLibraryHelper.removeNativeBinariesLI(childPs
+ .legacyNativeLibraryPathString);
+ }
}
}
}
@@ -14464,7 +14440,7 @@
private boolean deleteSystemPackageLI(PackageParser.Package deletedPkg,
PackageSetting deletedPs, int[] allUserHandles, int flags, PackageRemovedInfo outInfo,
boolean writeSettings) {
- if (deletedPkg.parentPackage != null) {
+ if (deletedPs.parentPackageName != null) {
Slog.w(TAG, "Attempt to delete child system package " + deletedPkg.packageName);
return false;
}
@@ -14477,7 +14453,7 @@
// the system pkg from system partition
// reader
synchronized (mPackages) {
- disabledPs = mSettings.getDisabledSystemPkgLPr(deletedPkg.packageName);
+ disabledPs = mSettings.getDisabledSystemPkgLPr(deletedPs.name);
}
if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.packageName
@@ -14503,10 +14479,10 @@
// Delete the updated package
outInfo.isRemovedPackageSystemUpdate = true;
if (outInfo.removedChildPackages != null) {
- final int childCount = (deletedPkg.childPackages != null)
- ? deletedPkg.childPackages.size() : 0;
+ final int childCount = (deletedPs.childPackageNames != null)
+ ? deletedPs.childPackageNames.size() : 0;
for (int i = 0; i < childCount; i++) {
- String childPackageName = deletedPkg.childPackages.get(i).packageName;
+ String childPackageName = deletedPs.childPackageNames.get(i);
if (disabledPs.childPackageNames != null && disabledPs.childPackageNames
.contains(childPackageName)) {
PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
@@ -14526,7 +14502,7 @@
flags |= PackageManager.DELETE_KEEP_DATA;
}
- boolean ret = deleteInstalledPackageLI(deletedPkg, true, flags, allUserHandles,
+ boolean ret = deleteInstalledPackageLI(deletedPs, true, flags, allUserHandles,
outInfo, writeSettings, disabledPs.pkg);
if (!ret) {
return false;
@@ -14537,7 +14513,7 @@
// Reinstate the old system package
enableSystemPackageLPw(disabledPs.pkg);
// Remove any native libraries from the upgraded package.
- removeNativeBinariesLI(deletedPkg);
+ removeNativeBinariesLI(deletedPs);
}
// Install the system package
@@ -14594,29 +14570,18 @@
return true;
}
- private boolean deleteInstalledPackageLI(PackageParser.Package pkg,
+ private boolean deleteInstalledPackageLI(PackageSetting ps,
boolean deleteCodeAndResources, int flags, int[] allUserHandles,
PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
- PackageSetting ps = null;
-
synchronized (mPackages) {
- pkg = mPackages.get(pkg.packageName);
- if (pkg == null) {
- return false;
- }
-
- ps = mSettings.mPackages.get(pkg.packageName);
- if (ps == null) {
- return false;
- }
-
if (outInfo != null) {
outInfo.uid = ps.appId;
}
if (outInfo != null && outInfo.removedChildPackages != null) {
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+ final int childCount = (ps.childPackageNames != null)
+ ? ps.childPackageNames.size() : 0;
for (int i = 0; i < childCount; i++) {
String childPackageName = ps.childPackageNames.get(i);
PackageSetting childPs = mSettings.mPackages.get(childPackageName);
@@ -14636,11 +14601,11 @@
removePackageDataLI(ps, allUserHandles, outInfo, flags, writeSettings);
// Delete the child packages data
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+ final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageSetting childPs;
synchronized (mPackages) {
- childPs = mSettings.peekPackageLPr(pkg.childPackages.get(i).packageName);
+ childPs = mSettings.peekPackageLPr(ps.childPackageNames.get(i));
}
if (childPs != null) {
PackageRemovedInfo childOutInfo = (outInfo != null
@@ -14656,7 +14621,7 @@
}
// Delete application code and resources only for parent packages
- if (ps.pkg.parentPackage == null) {
+ if (ps.parentPackageName == null) {
if (deleteCodeAndResources && (outInfo != null)) {
outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
@@ -14747,7 +14712,7 @@
return false;
}
- if (ps.pkg != null && ps.pkg.parentPackage != null && (!isSystemApp(ps)
+ if (ps.parentPackageName != null && (!isSystemApp(ps)
|| (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) {
if (DEBUG_REMOVE) {
Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:"
@@ -14835,7 +14800,7 @@
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
// Kill application pre-emptively especially for apps on sd.
killApplication(packageName, ps.appId, "uninstall pkg");
- ret = deleteInstalledPackageLI(ps.pkg, deleteCodeAndResources, flags, allUserHandles,
+ ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, allUserHandles,
outInfo, writeSettings, replacingPackage);
}
@@ -18021,6 +17986,13 @@
if (ps.getInstalled(userId)) {
prepareAppData(volumeUuid, userId, flags, ps.pkg, restoreconNeeded);
+
+ if (maybeMigrateAppData(volumeUuid, userId, ps.pkg)) {
+ // We may have just shuffled around app data directories, so
+ // prepare them one more time
+ prepareAppData(volumeUuid, userId, flags, ps.pkg, restoreconNeeded);
+ }
+
preparedCount++;
}
}
@@ -18148,6 +18120,30 @@
}
}
+ /**
+ * For system apps on non-FBE devices, this method migrates any existing
+ * CE/DE data to match the {@code forceDeviceEncrypted} flag requested by
+ * the app.
+ */
+ private boolean maybeMigrateAppData(String volumeUuid, int userId, PackageParser.Package pkg) {
+ if (pkg.isSystemApp() && !StorageManager.isFileBasedEncryptionEnabled()
+ && PackageManager.APPLY_FORCE_DEVICE_ENCRYPTED) {
+ final int storageTarget = pkg.applicationInfo.isForceDeviceEncrypted()
+ ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
+ synchronized (mInstallLock) {
+ try {
+ mInstaller.migrateAppData(volumeUuid, pkg.packageName, userId, storageTarget);
+ } catch (InstallerException e) {
+ logCriticalInfo(Log.WARN,
+ "Failed to migrate " + pkg.packageName + ": " + e.getMessage());
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
private void unfreezePackage(String packageName) {
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 094b3a9..1b70d65 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -181,7 +181,10 @@
* @hide
*/
public void removeCapability(int capability) {
- mConnectionCapabilities &= ~capability;
+ int newCapabilities = mConnectionCapabilities;
+ newCapabilities &= ~capability;
+
+ setConnectionCapabilities(newCapabilities);
}
/**
@@ -191,7 +194,10 @@
* @hide
*/
public void addCapability(int capability) {
- mConnectionCapabilities |= capability;
+ int newCapabilities = mConnectionCapabilities;
+ newCapabilities |= capability;
+
+ setConnectionCapabilities(newCapabilities);
}
/**
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 9f478df..857d2df 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1426,6 +1426,7 @@
* {@link android.provider.BlockedNumberContract#canCurrentUserBlockNumbers(Context)} returns
* {@code true} for the current user.
*/
+ // TODO: Delete this.
public void launchManageBlockedNumbersActivity() {
ITelecomService service = getTelecomService();
if (service != null) {
@@ -1437,6 +1438,26 @@
}
}
+ /**
+ * Creates the {@link Intent} which can be used with {@link Context#startActivity(Intent)} to
+ * launch the activity to manage blocked numbers.
+ * <p> This method displays the UI to manage blocked numbers only if
+ * {@link android.provider.BlockedNumberContract#canCurrentUserBlockNumbers(Context)} returns
+ * {@code true} for the current user.
+ */
+ public Intent createManageBlockedNumbersIntent() {
+ ITelecomService service = getTelecomService();
+ Intent result = null;
+ if (service != null) {
+ try {
+ result = service.createManageBlockedNumbersIntent();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecomService#createManageBlockedNumbersIntent", e);
+ }
+ }
+ return result;
+ }
+
private ITelecomService getTelecomService() {
if (mTelecomServiceOverride != null) {
return mTelecomServiceOverride;
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 95c8db5..3c250f1 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -17,6 +17,7 @@
package com.android.internal.telecom;
import android.content.ComponentName;
+import android.content.Intent;
import android.telecom.ParcelableCallAnalytics;
import android.telecom.PhoneAccountHandle;
import android.net.Uri;
@@ -247,5 +248,11 @@
/**
* @see TelecomServiceImpl#launchManageBlockedNumbersActivity
**/
+ // TODO: Delete this.
void launchManageBlockedNumbersActivity(in String callingPackageName);
+
+ /**
+ * @see TelecomServiceImpl#createManageBlockedNumbersIntent
+ **/
+ Intent createManageBlockedNumbersIntent();
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java
index 91161f5..024e32f 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java
@@ -16,9 +16,11 @@
package com.android.tools.layoutlib.create;
+import java.util.Arrays;
import java.util.HashMap;
import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
public class RefactorClassAdapter extends AbstractClassAdapter {
@@ -30,6 +32,14 @@
}
@Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
+ MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
+
+ return new RefactorStackMapAdapter(mw);
+ }
+
+ @Override
protected String renameInternalType(String oldClassName) {
if (oldClassName != null) {
String newName = mRefactorClasses.get(oldClassName);
@@ -46,4 +56,49 @@
}
return oldClassName;
}
+
+ /**
+ * A method visitor that renames all references from an old class name to a new class name in
+ * the stackmap of the method.
+ */
+ private class RefactorStackMapAdapter extends MethodVisitor {
+
+ private RefactorStackMapAdapter(MethodVisitor mv) {
+ super(Main.ASM_VERSION, mv);
+ }
+
+
+ private Object[] renameFrame(Object[] elements) {
+ if (elements == null) {
+ return null;
+ }
+
+ // The input array cannot be modified. We only copy the source array on write
+ boolean copied = false;
+ for (int i = 0; i < elements.length; i++) {
+ if (!(elements[i] instanceof String)) {
+ continue;
+ }
+
+ if (!copied) {
+ elements = Arrays.copyOf(elements, elements.length);
+ copied = true;
+ }
+
+ String type = (String)elements[i];
+ if (type.indexOf(';') > 0) {
+ elements[i] = renameTypeDesc(type);
+ } else {
+ elements[i] = renameInternalType(type);
+ }
+ }
+
+ return elements;
+ }
+
+ @Override
+ public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
+ super.visitFrame(type, nLocal, renameFrame(local), nStack, renameFrame(stack));
+ }
+ }
}