diff options
48 files changed, 676 insertions, 1266 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index fcab8c10db9e..c58b91e39d0f 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1555,6 +1555,7 @@ public class AppOpsManager { private final long[] mRejectTimes; private final int mDuration; private final int mProxyUid; + private final boolean mRunning; private final String mProxyPackageName; public OpEntry(int op, int mode, long time, long rejectTime, int duration, @@ -1566,12 +1567,13 @@ public class AppOpsManager { mTimes[0] = time; mRejectTimes[0] = rejectTime; mDuration = duration; + mRunning = duration == -1; mProxyUid = proxyUid; mProxyPackageName = proxyPackage; } public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration, - int proxyUid, String proxyPackage) { + boolean running, int proxyUid, String proxyPackage) { mOp = op; mMode = mode; mTimes = new long[_NUM_UID_STATE]; @@ -1579,10 +1581,16 @@ public class AppOpsManager { System.arraycopy(times, 0, mTimes, 0, _NUM_UID_STATE); System.arraycopy(rejectTimes, 0, mRejectTimes, 0, _NUM_UID_STATE); mDuration = duration; + mRunning = running; mProxyUid = proxyUid; mProxyPackageName = proxyPackage; } + public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration, + int proxyUid, String proxyPackage) { + this(op, mode, times, rejectTimes, duration, duration == -1, proxyUid, proxyPackage); + } + public int getOp() { return mOp; } @@ -1632,7 +1640,7 @@ public class AppOpsManager { } public boolean isRunning() { - return mDuration == -1; + return mRunning; } public int getDuration() { @@ -1659,6 +1667,7 @@ public class AppOpsManager { dest.writeLongArray(mTimes); dest.writeLongArray(mRejectTimes); dest.writeInt(mDuration); + dest.writeBoolean(mRunning); dest.writeInt(mProxyUid); dest.writeString(mProxyPackageName); } @@ -1669,6 +1678,7 @@ public class AppOpsManager { mTimes = source.createLongArray(); mRejectTimes = source.createLongArray(); mDuration = source.readInt(); + mRunning = source.readBoolean(); mProxyUid = source.readInt(); mProxyPackageName = source.readString(); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 15aedd7cf502..63de8bf49f8b 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1664,7 +1664,8 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device includes at least one form of audio - * output, such as speakers, audio jack or streaming over bluetooth + * output, as defined in the Android Compatibility Definition Document (CDD) + * <a href="https://source.android.com/compatibility/android-cdd#7_8_audio">section 7.8 Audio</a>. */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output"; diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 2d8b4d482b21..c86149907323 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -43,7 +43,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false"); DEFAULT_FLAGS.put("settings_data_usage_v2", "true"); DEFAULT_FLAGS.put("settings_audio_switcher", "true"); - DEFAULT_FLAGS.put("settings_systemui_theme", "false"); + DEFAULT_FLAGS.put("settings_systemui_theme", "true"); } /** diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java index 294007946c77..9171959537c8 100644 --- a/core/java/com/android/internal/app/AssistUtils.java +++ b/core/java/com/android/internal/app/AssistUtils.java @@ -156,9 +156,12 @@ public class AssistUtils { if (activeServiceSupportsAssistGesture()) { return getActiveServiceComponentName(); } - - Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(false); + final SearchManager searchManager = + (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); + if (searchManager == null) { + return null; + } + final Intent intent = searchManager.getAssistIntent(false); PackageManager pm = mContext.getPackageManager(); ResolveInfo info = pm.resolveActivityAsUser(intent, PackageManager.MATCH_DEFAULT_ONLY, userId); diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 571878d183ee..4f567d239896 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -76,6 +76,7 @@ import android.widget.Space; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.app.ResolverActivity; import com.android.internal.app.ResolverActivity.TargetInfo; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -932,7 +933,7 @@ public class ChooserActivity extends ResolverActivity { public static final int TARGET_SERVICE = 1; public static final int TARGET_STANDARD = 2; - private static final int MAX_SERVICE_TARGETS = 8; + private static final int MAX_SERVICE_TARGETS = 4; private static final int MAX_TARGETS_PER_SERVICE = 4; private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>(); @@ -1189,123 +1190,20 @@ public class ChooserActivity extends ResolverActivity { } } - static class RowScale { - private static final int DURATION = 400; - - float mScale; - ChooserRowAdapter mAdapter; - private final ObjectAnimator mAnimator; - - public static final FloatProperty<RowScale> PROPERTY = - new FloatProperty<RowScale>("scale") { - @Override - public void setValue(RowScale object, float value) { - object.mScale = value; - object.mAdapter.notifyDataSetChanged(); - } - - @Override - public Float get(RowScale object) { - return object.mScale; - } - }; - - public RowScale(@NonNull ChooserRowAdapter adapter, float from, float to) { - mAdapter = adapter; - mScale = from; - if (from == to) { - mAnimator = null; - return; - } - - mAnimator = ObjectAnimator.ofFloat(this, PROPERTY, from, to) - .setDuration(DURATION); - mAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mAdapter.onAnimationStart(); - } - @Override - public void onAnimationEnd(Animator animation) { - mAdapter.onAnimationEnd(); - } - }); - } - - public RowScale setInterpolator(Interpolator interpolator) { - if (mAnimator != null) { - mAnimator.setInterpolator(interpolator); - } - return this; - } - - public float get() { - return mScale; - } - - public void startAnimation() { - if (mAnimator != null) { - mAnimator.start(); - } - } - - public void cancelAnimation() { - if (mAnimator != null) { - mAnimator.cancel(); - } - } - } - class ChooserRowAdapter extends BaseAdapter { private ChooserListAdapter mChooserListAdapter; private final LayoutInflater mLayoutInflater; private final int mColumnCount = 4; - private RowScale[] mServiceTargetScale; - private final Interpolator mInterpolator; private int mAnimationCount = 0; public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) { mChooserListAdapter = wrappedAdapter; mLayoutInflater = LayoutInflater.from(ChooserActivity.this); - mInterpolator = AnimationUtils.loadInterpolator(ChooserActivity.this, - android.R.interpolator.decelerate_quint); - wrappedAdapter.registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { super.onChanged(); - final int rcount = getServiceTargetRowCount(); - if (mServiceTargetScale == null - || mServiceTargetScale.length != rcount) { - RowScale[] old = mServiceTargetScale; - int oldRCount = old != null ? old.length : 0; - mServiceTargetScale = new RowScale[rcount]; - if (old != null && rcount > 0) { - System.arraycopy(old, 0, mServiceTargetScale, 0, - Math.min(old.length, rcount)); - } - - for (int i = rcount; i < oldRCount; i++) { - old[i].cancelAnimation(); - } - - for (int i = oldRCount; i < rcount; i++) { - final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f) - .setInterpolator(mInterpolator); - mServiceTargetScale[i] = rs; - } - - // Start the animations in a separate loop. - // The process of starting animations will result in - // binding views to set up initial values, and we must - // have ALL of the new RowScale objects created above before - // we get started. - for (int i = oldRCount; i < rcount; i++) { - mServiceTargetScale[i].startAnimation(); - } - } - notifyDataSetChanged(); } @@ -1313,39 +1211,10 @@ public class ChooserActivity extends ResolverActivity { public void onInvalidated() { super.onInvalidated(); notifyDataSetInvalidated(); - if (mServiceTargetScale != null) { - for (RowScale rs : mServiceTargetScale) { - rs.cancelAnimation(); - } - } } }); } - private float getRowScale(int rowPosition) { - final int start = getCallerTargetRowCount(); - final int end = start + getServiceTargetRowCount(); - if (rowPosition >= start && rowPosition < end) { - return mServiceTargetScale[rowPosition - start].get(); - } - return 1.f; - } - - public void onAnimationStart() { - final boolean lock = mAnimationCount == 0; - mAnimationCount++; - if (lock) { - mResolverDrawerLayout.setDismissLocked(true); - } - } - - public void onAnimationEnd() { - mAnimationCount--; - if (mAnimationCount == 0) { - mResolverDrawerLayout.setDismissLocked(false); - } - } - @Override public int getCount() { return (int) ( @@ -1360,9 +1229,9 @@ public class ChooserActivity extends ResolverActivity { (float) mChooserListAdapter.getCallerTargetCount() / mColumnCount); } + // There can be at most one row of service targets. public int getServiceTargetRowCount() { - return (int) Math.ceil( - (float) mChooserListAdapter.getServiceTargetCount() / mColumnCount); + return (int) mChooserListAdapter.getServiceTargetCount() == 0 ? 0 : 1; } @Override @@ -1485,8 +1354,7 @@ public class ChooserActivity extends ResolverActivity { } final int oldHeight = holder.row.getLayoutParams().height; - holder.row.getLayoutParams().height = Math.max(1, - (int) (holder.measuredRowHeight * getRowScale(rowPosition))); + holder.row.getLayoutParams().height = Math.max(1, holder.measuredRowHeight); if (holder.row.getLayoutParams().height != oldHeight) { holder.row.requestLayout(); } @@ -1728,7 +1596,7 @@ public class ChooserActivity extends ResolverActivity { final View v = mChooserRowAdapter.getView(pos, mCachedView, mListView); int height = ((RowViewHolder) (v.getTag())).measuredRowHeight; - offset += (int) (height * mChooserRowAdapter.getRowScale(pos)); + offset += (int) (height); if (vt >= 0) { mCachedViewType = vt; diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java index d1350403b32c..c9a916187d33 100644 --- a/core/java/com/android/internal/widget/MessagingGroup.java +++ b/core/java/com/android/internal/widget/MessagingGroup.java @@ -100,7 +100,6 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou super.onFinishInflate(); mMessageContainer = findViewById(R.id.group_message_container); mSenderName = findViewById(R.id.message_name); - mSenderName.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR); mAvatarView = findViewById(R.id.message_icon); mImageContainer = findViewById(R.id.messaging_group_icon_container); mSendingSpinner = findViewById(R.id.messaging_group_sending_progress); @@ -190,73 +189,66 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou } public void removeMessage(MessagingMessage messagingMessage) { - ViewGroup messageParent = (ViewGroup) messagingMessage.getView().getParent(); - messageParent.removeView(messagingMessage.getView()); + View view = messagingMessage.getView(); + boolean wasShown = view.isShown(); + ViewGroup messageParent = (ViewGroup) view.getParent(); + if (messageParent == null) { + return; + } + messageParent.removeView(view); Runnable recycleRunnable = () -> { - messageParent.removeTransientView(messagingMessage.getView()); + messageParent.removeTransientView(view); messagingMessage.recycle(); - if (mMessageContainer.getChildCount() == 0 - && mMessageContainer.getTransientViewCount() == 0 - && mImageContainer.getChildCount() == 0) { - ViewParent parent = getParent(); - if (parent instanceof ViewGroup) { - ((ViewGroup) parent).removeView(MessagingGroup.this); - } - setAvatar(null); - mAvatarView.setAlpha(1.0f); - mAvatarView.setTranslationY(0.0f); - mSenderName.setAlpha(1.0f); - mSenderName.setTranslationY(0.0f); - mIsolatedMessage = null; - mMessages = null; - sInstancePool.release(MessagingGroup.this); - } }; - if (isShown()) { - messageParent.addTransientView(messagingMessage.getView(), 0); - performRemoveAnimation(messagingMessage.getView(), recycleRunnable); - if (mMessageContainer.getChildCount() == 0 - && mImageContainer.getChildCount() == 0) { - removeGroupAnimated(null); - } + if (wasShown && !MessagingLinearLayout.isGone(view)) { + messageParent.addTransientView(view, 0); + performRemoveAnimation(view, recycleRunnable); } else { recycleRunnable.run(); } - } - private void removeGroupAnimated(Runnable endAction) { - performRemoveAnimation(mAvatarView, null); - performRemoveAnimation(mSenderName, null); - boolean endActionTriggered = false; - for (int i = mMessageContainer.getChildCount() - 1; i >= 0; i--) { - View child = mMessageContainer.getChildAt(i); - if (child.getVisibility() == View.GONE) { - continue; - } - final ViewGroup.LayoutParams lp = child.getLayoutParams(); - if (lp instanceof MessagingLinearLayout.LayoutParams - && ((MessagingLinearLayout.LayoutParams) lp).hide - && !((MessagingLinearLayout.LayoutParams) lp).visibleBefore) { - continue; - } - Runnable childEndAction = endActionTriggered ? null : endAction; - performRemoveAnimation(child, childEndAction); - endActionTriggered = true; - } + public void recycle() { if (mIsolatedMessage != null) { - performRemoveAnimation(mIsolatedMessage, !endActionTriggered ? endAction : null); - endActionTriggered = true; + mImageContainer.removeView(mIsolatedMessage); } - if (!endActionTriggered && endAction != null) { - endAction.run(); + for (int i = 0; i < mMessages.size(); i++) { + MessagingMessage message = mMessages.get(i); + mMessageContainer.removeView(message.getView()); + message.recycle(); } + setAvatar(null); + mAvatarView.setAlpha(1.0f); + mAvatarView.setTranslationY(0.0f); + mSenderName.setAlpha(1.0f); + mSenderName.setTranslationY(0.0f); + setAlpha(1.0f); + mIsolatedMessage = null; + mMessages = null; + mAddedMessages.clear(); + mFirstLayout = true; + MessagingPropertyAnimator.recycle(this); + sInstancePool.release(MessagingGroup.this); + } + + public void removeGroupAnimated(Runnable endAction) { + performRemoveAnimation(this, () -> { + setAlpha(1.0f); + MessagingPropertyAnimator.setToLaidOutPosition(this); + if (endAction != null) { + endAction.run(); + } + }); } public void performRemoveAnimation(View message, Runnable endAction) { - MessagingPropertyAnimator.fadeOut(message, endAction); - MessagingPropertyAnimator.startLocalTranslationTo(message, - (int) (-getHeight() * 0.5f), MessagingLayout.FAST_OUT_LINEAR_IN); + performRemoveAnimation(message, -message.getHeight(), endAction); + } + + private void performRemoveAnimation(View view, int disappearTranslation, Runnable endAction) { + MessagingPropertyAnimator.startLocalTranslationTo(view, disappearTranslation, + MessagingLayout.FAST_OUT_LINEAR_IN); + MessagingPropertyAnimator.fadeOut(view, endAction); } public CharSequence getSenderName() { @@ -341,6 +333,11 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou } } + @Override + public boolean hasOverlappingRendering() { + return false; + } + public Icon getAvatarSymbolIfMatching(CharSequence avatarName, String avatarSymbol, int layoutColor) { if (mAvatarName.equals(avatarName) && mAvatarSymbol.equals(avatarSymbol) @@ -458,6 +455,7 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (!mAddedMessages.isEmpty()) { + final boolean firstLayout = mFirstLayout; getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { @@ -466,7 +464,7 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou continue; } MessagingPropertyAnimator.fadeIn(message.getView()); - if (!mFirstLayout) { + if (!firstLayout) { MessagingPropertyAnimator.startLocalTranslationFrom(message.getView(), message.getView().getHeight(), MessagingLayout.LINEAR_OUT_SLOW_IN); diff --git a/core/java/com/android/internal/widget/MessagingImageMessage.java b/core/java/com/android/internal/widget/MessagingImageMessage.java index 9db74e82e382..607a3a9ab542 100644 --- a/core/java/com/android/internal/widget/MessagingImageMessage.java +++ b/core/java/com/android/internal/widget/MessagingImageMessage.java @@ -170,8 +170,6 @@ public class MessagingImageMessage extends ImageView implements MessagingMessage public void recycle() { MessagingMessage.super.recycle(); - setAlpha(1.0f); - setTranslationY(0); setImageBitmap(null); mDrawable = null; sInstancePool.release(this); diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java index 03a734d8537e..0fd610908fd5 100644 --- a/core/java/com/android/internal/widget/MessagingLayout.java +++ b/core/java/com/android/internal/widget/MessagingLayout.java @@ -180,8 +180,13 @@ public class MessagingLayout extends FrameLayout { List<MessagingMessage> historicMessages = createMessages(newHistoricMessages, true /* isHistoric */); List<MessagingMessage> messages = createMessages(newMessages, false /* isHistoric */); + + ArrayList<MessagingGroup> oldGroups = new ArrayList<>(mGroups); addMessagesToGroups(historicMessages, messages, showSpinner); + // Let's first check which groups were removed altogether and remove them in one animation + removeGroups(oldGroups); + // Let's remove the remaining messages mMessages.forEach(REMOVE_MESSAGE); mHistoricMessages.forEach(REMOVE_MESSAGE); @@ -193,6 +198,31 @@ public class MessagingLayout extends FrameLayout { updateTitleAndNamesDisplay(); } + private void removeGroups(ArrayList<MessagingGroup> oldGroups) { + int size = oldGroups.size(); + for (int i = 0; i < size; i++) { + MessagingGroup group = oldGroups.get(i); + if (!mGroups.contains(group)) { + List<MessagingMessage> messages = group.getMessages(); + Runnable endRunnable = () -> { + mMessagingLinearLayout.removeTransientView(group); + group.recycle(); + }; + + boolean wasShown = group.isShown(); + mMessagingLinearLayout.removeView(group); + if (wasShown && !MessagingLinearLayout.isGone(group)) { + mMessagingLinearLayout.addTransientView(group, 0); + group.removeGroupAnimated(endRunnable); + } else { + endRunnable.run(); + } + mMessages.removeAll(messages); + mHistoricMessages.removeAll(messages); + } + } + } + private void updateTitleAndNamesDisplay() { ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>(); ArrayMap<Character, CharSequence> uniqueCharacters = new ArrayMap<>(); diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java index 991e3e7a80f9..64b1f241464b 100644 --- a/core/java/com/android/internal/widget/MessagingLinearLayout.java +++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java @@ -163,15 +163,6 @@ public class MessagingLinearLayout extends ViewGroup { } final LayoutParams lp = (LayoutParams) child.getLayoutParams(); MessagingChild messagingChild = (MessagingChild) child; - if (lp.hide) { - if (shown && lp.visibleBefore) { - messagingChild.hideAnimated(); - } - lp.visibleBefore = false; - continue; - } else { - lp.visibleBefore = true; - } final int childWidth = child.getMeasuredWidth(); final int childHeight = child.getMeasuredHeight(); @@ -182,6 +173,19 @@ public class MessagingLinearLayout extends ViewGroup { } else { childLeft = paddingLeft + lp.leftMargin; } + if (lp.hide) { + if (shown && lp.visibleBefore) { + // We still want to lay out the child to have great animations + child.layout(childLeft, childTop, childLeft + childWidth, + childTop + lp.lastVisibleHeight); + messagingChild.hideAnimated(); + } + lp.visibleBefore = false; + continue; + } else { + lp.visibleBefore = true; + lp.lastVisibleHeight = childHeight; + } if (!first) { childTop += mSpacing; @@ -228,6 +232,18 @@ public class MessagingLinearLayout extends ViewGroup { return copy; } + public static boolean isGone(View view) { + if (view.getVisibility() == View.GONE) { + return true; + } + final ViewGroup.LayoutParams lp = view.getLayoutParams(); + if (lp instanceof MessagingLinearLayout.LayoutParams + && ((MessagingLinearLayout.LayoutParams) lp).hide) { + return true; + } + return false; + } + /** * Sets how many lines should be displayed at most */ @@ -263,6 +279,7 @@ public class MessagingLinearLayout extends ViewGroup { public boolean hide = false; public boolean visibleBefore = false; + public int lastVisibleHeight; public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java index ffcb50309feb..74d0aae3634b 100644 --- a/core/java/com/android/internal/widget/MessagingMessage.java +++ b/core/java/com/android/internal/widget/MessagingMessage.java @@ -124,8 +124,7 @@ public interface MessagingMessage extends MessagingLinearLayout.MessagingChild { @Override default void hideAnimated() { setIsHidingAnimated(true); - getGroup().performRemoveAnimation(getState().getHostView(), - () -> setIsHidingAnimated(false)); + getGroup().performRemoveAnimation(getView(), () -> setIsHidingAnimated(false)); } default boolean hasOverlappingRendering() { @@ -133,7 +132,7 @@ public interface MessagingMessage extends MessagingLinearLayout.MessagingChild { } default void recycle() { - getState().reset(); + getState().recycle(); } default View getView() { diff --git a/core/java/com/android/internal/widget/MessagingMessageState.java b/core/java/com/android/internal/widget/MessagingMessageState.java index ac624728689d..1ba2b51dec44 100644 --- a/core/java/com/android/internal/widget/MessagingMessageState.java +++ b/core/java/com/android/internal/widget/MessagingMessageState.java @@ -72,7 +72,10 @@ public class MessagingMessageState { return mHostView; } - public void reset() { + public void recycle() { + mHostView.setAlpha(1.0f); + mHostView.setTranslationY(0); + MessagingPropertyAnimator.recycle(mHostView); mIsHidingAnimated = false; mIsHistoric = false; mGroup = null; diff --git a/core/java/com/android/internal/widget/MessagingPropertyAnimator.java b/core/java/com/android/internal/widget/MessagingPropertyAnimator.java index 7c3ab7f9547f..7703cb0f13db 100644 --- a/core/java/com/android/internal/widget/MessagingPropertyAnimator.java +++ b/core/java/com/android/internal/widget/MessagingPropertyAnimator.java @@ -31,111 +31,125 @@ import com.android.internal.R; * A listener that automatically starts animations when the layout bounds change. */ public class MessagingPropertyAnimator implements View.OnLayoutChangeListener { - static final long APPEAR_ANIMATION_LENGTH = 210; + private static final long APPEAR_ANIMATION_LENGTH = 210; private static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f); - private static final int TAG_LOCAL_TRANSLATION_ANIMATOR = R.id.tag_local_translation_y_animator; - private static final int TAG_LOCAL_TRANSLATION_Y = R.id.tag_local_translation_y; + private static final int TAG_TOP_ANIMATOR = R.id.tag_top_animator; + private static final int TAG_TOP = R.id.tag_top_override; private static final int TAG_LAYOUT_TOP = R.id.tag_layout_top; + private static final int TAG_FIRST_LAYOUT = R.id.tag_is_first_layout; private static final int TAG_ALPHA_ANIMATOR = R.id.tag_alpha_animator; private static final ViewClippingUtil.ClippingParameters CLIPPING_PARAMETERS = view -> view.getId() == com.android.internal.R.id.notification_messaging; - private static final IntProperty<View> LOCAL_TRANSLATION_Y = - new IntProperty<View>("localTranslationY") { + private static final IntProperty<View> TOP = + new IntProperty<View>("top") { @Override public void setValue(View object, int value) { - setLocalTranslationY(object, value); + setTop(object, value); } @Override public Integer get(View object) { - return getLocalTranslationY(object); + return getTop(object); } }; @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - int oldHeight = oldBottom - oldTop; - Integer layoutTop = (Integer) v.getTag(TAG_LAYOUT_TOP); - if (layoutTop != null) { - oldTop = layoutTop; - } - int topChange = oldTop - top; - if (oldHeight == 0 || topChange == 0 || !v.isShown() || isGone(v)) { - // First layout + setLayoutTop(v, top); + if (isFirstLayout(v)) { + setFirstLayout(v, false /* first */); + setTop(v, top); return; } - if (layoutTop != null) { - v.setTagInternal(TAG_LAYOUT_TOP, top); - } - int newHeight = bottom - top; - int heightDifference = oldHeight - newHeight; - // Only add the difference if the height changes and it's getting smaller - heightDifference = Math.max(heightDifference, 0); - startLocalTranslationFrom(v, topChange + heightDifference + getLocalTranslationY(v)); + startTopAnimation(v, getTop(v), top, MessagingLayout.FAST_OUT_SLOW_IN); } - private boolean isGone(View view) { - if (view.getVisibility() == View.GONE) { - return true; - } - final ViewGroup.LayoutParams lp = view.getLayoutParams(); - if (lp instanceof MessagingLinearLayout.LayoutParams - && ((MessagingLinearLayout.LayoutParams) lp).hide) { + private static boolean isFirstLayout(View view) { + Boolean tag = (Boolean) view.getTag(TAG_FIRST_LAYOUT); + if (tag == null) { return true; } - return false; + return tag; } - public static void startLocalTranslationFrom(View v, int startTranslation) { - startLocalTranslationFrom(v, startTranslation, MessagingLayout.FAST_OUT_SLOW_IN); + public static void recycle(View view) { + setFirstLayout(view, true /* first */); } - public static void startLocalTranslationFrom(View v, int startTranslation, + private static void setFirstLayout(View view, boolean first) { + view.setTagInternal(TAG_FIRST_LAYOUT, first); + } + + private static void setLayoutTop(View view, int top) { + view.setTagInternal(TAG_LAYOUT_TOP, top); + } + + public static int getLayoutTop(View view) { + Integer tag = (Integer) view.getTag(TAG_LAYOUT_TOP); + if (tag == null) { + return getTop(view); + } + return tag; + } + + /** + * Start a translation animation from a start offset to the laid out location + * @param view The view to animate + * @param startTranslation The starting translation to start from. + * @param interpolator The interpolator to use. + */ + public static void startLocalTranslationFrom(View view, int startTranslation, Interpolator interpolator) { - startLocalTranslation(v, startTranslation, 0, interpolator); + startTopAnimation(view, getTop(view) + startTranslation, getLayoutTop(view), interpolator); } - public static void startLocalTranslationTo(View v, int endTranslation, + /** + * Start a translation animation from a start offset to the laid out location + * @param view The view to animate + * @param endTranslation The end translation to go to. + * @param interpolator The interpolator to use. + */ + public static void startLocalTranslationTo(View view, int endTranslation, Interpolator interpolator) { - startLocalTranslation(v, getLocalTranslationY(v), endTranslation, interpolator); + int top = getTop(view); + startTopAnimation(view, top, top + endTranslation, interpolator); } - public static int getLocalTranslationY(View v) { - Integer tag = (Integer) v.getTag(TAG_LOCAL_TRANSLATION_Y); + public static int getTop(View v) { + Integer tag = (Integer) v.getTag(TAG_TOP); if (tag == null) { - return 0; + return v.getTop(); } return tag; } - private static void setLocalTranslationY(View v, int value) { - v.setTagInternal(TAG_LOCAL_TRANSLATION_Y, value); + private static void setTop(View v, int value) { + v.setTagInternal(TAG_TOP, value); updateTopAndBottom(v); } private static void updateTopAndBottom(View v) { - int layoutTop = (int) v.getTag(TAG_LAYOUT_TOP); - int localTranslation = getLocalTranslationY(v); + int top = getTop(v); int height = v.getHeight(); - v.setTop(layoutTop + localTranslation); - v.setBottom(layoutTop + height + localTranslation); + v.setTop(top); + v.setBottom(height + top); } - private static void startLocalTranslation(final View v, int start, int end, + private static void startTopAnimation(final View v, int start, int end, Interpolator interpolator) { - ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_LOCAL_TRANSLATION_ANIMATOR); + ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_TOP_ANIMATOR); if (existing != null) { existing.cancel(); } - ObjectAnimator animator = ObjectAnimator.ofInt(v, LOCAL_TRANSLATION_Y, start, end); - Integer layoutTop = (Integer) v.getTag(TAG_LAYOUT_TOP); - if (layoutTop == null) { - layoutTop = v.getTop(); - v.setTagInternal(TAG_LAYOUT_TOP, layoutTop); + if (!v.isShown() || start == end + || (MessagingLinearLayout.isGone(v) && !isHidingAnimated(v))) { + setTop(v, end); + return; } - setLocalTranslationY(v, start); + ObjectAnimator animator = ObjectAnimator.ofInt(v, TOP, start, end); + setTop(v, start); animator.setInterpolator(interpolator); animator.setDuration(APPEAR_ANIMATION_LENGTH); animator.addListener(new AnimatorListenerAdapter() { @@ -143,12 +157,8 @@ public class MessagingPropertyAnimator implements View.OnLayoutChangeListener { @Override public void onAnimationEnd(Animator animation) { - v.setTagInternal(TAG_LOCAL_TRANSLATION_ANIMATOR, null); + v.setTagInternal(TAG_TOP_ANIMATOR, null); setClippingDeactivated(v, false); - if (!mCancelled) { - setLocalTranslationY(v, 0); - v.setTagInternal(TAG_LAYOUT_TOP, null); - } } @Override @@ -157,10 +167,17 @@ public class MessagingPropertyAnimator implements View.OnLayoutChangeListener { } }); setClippingDeactivated(v, true); - v.setTagInternal(TAG_LOCAL_TRANSLATION_ANIMATOR, animator); + v.setTagInternal(TAG_TOP_ANIMATOR, animator); animator.start(); } + private static boolean isHidingAnimated(View v) { + if (v instanceof MessagingLinearLayout.MessagingChild) { + return ((MessagingLinearLayout.MessagingChild) v).isHidingAnimated(); + } + return false; + } + public static void fadeIn(final View v) { ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_ALPHA_ANIMATOR); if (existing != null) { @@ -199,6 +216,13 @@ public class MessagingPropertyAnimator implements View.OnLayoutChangeListener { if (existing != null) { existing.cancel(); } + if (!view.isShown() || (MessagingLinearLayout.isGone(view) && !isHidingAnimated(view))) { + view.setAlpha(0.0f); + if (endAction != null) { + endAction.run(); + } + return; + } ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.ALPHA, view.getAlpha(), 0.0f); animator.setInterpolator(ALPHA_OUT); @@ -224,10 +248,14 @@ public class MessagingPropertyAnimator implements View.OnLayoutChangeListener { } public static boolean isAnimatingTranslation(View v) { - return v.getTag(TAG_LOCAL_TRANSLATION_ANIMATOR) != null; + return v.getTag(TAG_TOP_ANIMATOR) != null; } public static boolean isAnimatingAlpha(View v) { return v.getTag(TAG_ALPHA_ANIMATOR) != null; } + + public static void setToLaidOutPosition(View view) { + setTop(view, getLayoutTop(view)); + } } diff --git a/core/java/com/android/internal/widget/MessagingTextMessage.java b/core/java/com/android/internal/widget/MessagingTextMessage.java index 219116e414f1..4081a866f993 100644 --- a/core/java/com/android/internal/widget/MessagingTextMessage.java +++ b/core/java/com/android/internal/widget/MessagingTextMessage.java @@ -92,8 +92,6 @@ public class MessagingTextMessage extends ImageFloatingTextView implements Messa public void recycle() { MessagingMessage.super.recycle(); - setAlpha(1.0f); - setTranslationY(0); sInstancePool.release(this); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 19e5e21d5093..dced0ad35c5f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -850,7 +850,7 @@ <!-- Used for permissions that are associated telephony features. --> <permission-group android:name="android.permission-group.CALL_LOG" - android:icon="@drawable/perm_group_phone_calls" + android:icon="@drawable/perm_group_call_log" android:label="@string/permgrouplab_calllog" android:description="@string/permgroupdesc_calllog" android:request="@string/permgrouprequest_calllog" diff --git a/core/res/res/drawable/perm_group_call_log.xml b/core/res/res/drawable/perm_group_call_log.xml new file mode 100644 index 000000000000..0dfdbee4e600 --- /dev/null +++ b/core/res/res/drawable/perm_group_call_log.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#000000" + android:pathData="M16.01,14.48l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.82c-0.09,-0.47 -0.5,-0.8 -0.98,-0.8L4,3.01c-0.56,0 -1.03,0.47 -1,1.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.26,-0.65C16.58,14.14 16.24,14.24 16.01,14.48z"/> + <path + android:fillColor="#000000" + android:pathData="M12,8h10V6H12V8zM12,4h10V2H12V4zM22,10H12v2h10V10z"/> +</vector> diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index 47d04edfc281..bf7e0682e91b 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -140,15 +140,18 @@ <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_MOVE_WINDOW}. --> <item type="id" name="accessibilityActionMoveWindow" /> - <!-- A tag used to save an animator in local y translation --> - <item type="id" name="tag_local_translation_y_animator" /> + <!-- A tag used to save an animator in top --> + <item type="id" name="tag_top_animator" /> - <!-- A tag used to save the local translation y --> - <item type="id" name="tag_local_translation_y" /> + <!-- A tag used to save the current top override --> + <item type="id" name="tag_top_override" /> <!-- A tag used to save the original top of a view --> <item type="id" name="tag_layout_top" /> + <!-- A tag used to save whether a view was laid out before --> + <item type="id" name="tag_is_first_layout" /> + <!-- A tag used to save an animator in alpha --> <item type="id" name="tag_alpha_animator" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index f7ff37738256..8a045a07938c 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3260,9 +3260,10 @@ <java-symbol type="id" name="message_name" /> <java-symbol type="id" name="message_icon" /> <java-symbol type="id" name="group_message_container" /> - <java-symbol type="id" name="tag_local_translation_y_animator" /> - <java-symbol type="id" name="tag_local_translation_y" /> + <java-symbol type="id" name="tag_top_animator" /> + <java-symbol type="id" name="tag_top_override" /> <java-symbol type="id" name="tag_layout_top" /> + <java-symbol type="id" name="tag_is_first_layout" /> <java-symbol type="id" name="tag_alpha_animator" /> <java-symbol type="id" name="clip_children_set_tag" /> <java-symbol type="id" name="clip_to_padding_tag" /> diff --git a/docs/html/reference/_book.yaml b/docs/html/reference/_book.yaml deleted file mode 100644 index b902a61a6501..000000000000 --- a/docs/html/reference/_book.yaml +++ /dev/null @@ -1,853 +0,0 @@ -reference: -- title: Class Index - path: /reference/classes.html - status_text: no-toggle -- title: Package Index - path: /reference/packages.html - status_text: no-toggle -- title: android - path: /reference/android/package-summary.html - status_text: apilevel-1 -- title: android.accessibilityservice - path: /reference/android/accessibilityservice/package-summary.html - status_text: apilevel-4 -- title: android.accounts - path: /reference/android/accounts/package-summary.html - status_text: apilevel-5 -- title: android.animation - path: /reference/android/animation/package-summary.html - status_text: apilevel-11 -- title: android.annotation - path: /reference/android/annotation/package-summary.html - status_text: apilevel-16 -- title: android.app - path: /reference/android/app/package-summary.html - status_text: apilevel-1 -- title: android.app.admin - path: /reference/android/app/admin/package-summary.html - status_text: apilevel-8 -- title: android.app.assist - path: /reference/android/app/assist/package-summary.html - status_text: apilevel-23 -- title: android.app.backup - path: /reference/android/app/backup/package-summary.html - status_text: apilevel-8 -- title: android.app.job - path: /reference/android/app/job/package-summary.html - status_text: apilevel-21 -- title: android.app.usage - path: /reference/android/app/usage/package-summary.html - status_text: apilevel-21 -- title: android.appwidget - path: /reference/android/appwidget/package-summary.html - status_text: apilevel-3 -- title: android.bluetooth - path: /reference/android/bluetooth/package-summary.html - status_text: apilevel-5 -- title: android.bluetooth.le - path: /reference/android/bluetooth/le/package-summary.html - status_text: apilevel-21 -- title: android.companion - path: /reference/android/companion/package-summary.html - status_text: apilevel-O -- title: android.content - path: /reference/android/content/package-summary.html - status_text: apilevel-1 -- title: android.content.pm - path: /reference/android/content/pm/package-summary.html - status_text: apilevel-1 -- title: android.content.res - path: /reference/android/content/res/package-summary.html - status_text: apilevel-1 -- title: android.database - path: /reference/android/database/package-summary.html - status_text: apilevel-1 -- title: android.database.sqlite - path: /reference/android/database/sqlite/package-summary.html - status_text: apilevel-1 -- title: android.databinding - path: /reference/android/databinding/package-summary.html - status_text: apilevel- -- title: android.drm - path: /reference/android/drm/package-summary.html - status_text: apilevel-11 -- title: android.gesture - path: /reference/android/gesture/package-summary.html - status_text: apilevel-4 -- title: android.graphics - path: /reference/android/graphics/package-summary.html - status_text: apilevel-1 -- title: android.graphics.drawable - path: /reference/android/graphics/drawable/package-summary.html - status_text: apilevel-1 -- title: android.graphics.drawable.shapes - path: /reference/android/graphics/drawable/shapes/package-summary.html - status_text: apilevel-1 -- title: android.graphics.fonts - path: /reference/android/graphics/fonts/package-summary.html - status_text: apilevel-O -- title: android.graphics.pdf - path: /reference/android/graphics/pdf/package-summary.html - status_text: apilevel-19 -- title: android.hardware - path: /reference/android/hardware/package-summary.html - status_text: apilevel-1 -- title: android.hardware.camera2 - path: /reference/android/hardware/camera2/package-summary.html - status_text: apilevel-21 -- title: android.hardware.camera2.params - path: /reference/android/hardware/camera2/params/package-summary.html - status_text: apilevel-21 -- title: android.hardware.display - path: /reference/android/hardware/display/package-summary.html - status_text: apilevel-17 -- title: android.hardware.fingerprint - path: /reference/android/hardware/fingerprint/package-summary.html - status_text: apilevel-23 -- title: android.hardware.input - path: /reference/android/hardware/input/package-summary.html - status_text: apilevel-16 -- title: android.hardware.usb - path: /reference/android/hardware/usb/package-summary.html - status_text: apilevel-12 -- title: android.icu.lang - path: /reference/android/icu/lang/package-summary.html - status_text: apilevel-24 -- title: android.icu.math - path: /reference/android/icu/math/package-summary.html - status_text: apilevel-24 -- title: android.icu.text - path: /reference/android/icu/text/package-summary.html - status_text: apilevel-24 -- title: android.icu.util - path: /reference/android/icu/util/package-summary.html - status_text: apilevel-24 -- title: android.inputmethodservice - path: /reference/android/inputmethodservice/package-summary.html - status_text: apilevel-3 -- title: android.location - path: /reference/android/location/package-summary.html - status_text: apilevel-1 -- title: android.media - path: /reference/android/media/package-summary.html - status_text: apilevel-1 -- title: android.media.audiofx - path: /reference/android/media/audiofx/package-summary.html - status_text: apilevel-9 -- title: android.media.browse - path: /reference/android/media/browse/package-summary.html - status_text: apilevel-21 -- title: android.media.effect - path: /reference/android/media/effect/package-summary.html - status_text: apilevel-14 -- title: android.media.midi - path: /reference/android/media/midi/package-summary.html - status_text: apilevel-23 -- title: android.media.projection - path: /reference/android/media/projection/package-summary.html - status_text: apilevel-21 -- title: android.media.session - path: /reference/android/media/session/package-summary.html - status_text: apilevel-21 -- title: android.media.tv - path: /reference/android/media/tv/package-summary.html - status_text: apilevel-21 -- title: android.mtp - path: /reference/android/mtp/package-summary.html - status_text: apilevel-12 -- title: android.net - path: /reference/android/net/package-summary.html - status_text: apilevel-1 -- title: android.net.http - path: /reference/android/net/http/package-summary.html - status_text: apilevel-1 -- title: android.net.nsd - path: /reference/android/net/nsd/package-summary.html - status_text: apilevel-16 -- title: android.net.rtp - path: /reference/android/net/rtp/package-summary.html - status_text: apilevel-12 -- title: android.net.sip - path: /reference/android/net/sip/package-summary.html - status_text: apilevel-9 -- title: android.net.wifi - path: /reference/android/net/wifi/package-summary.html - status_text: apilevel-1 -- title: android.net.wifi.aware - path: /reference/android/net/wifi/aware/package-summary.html - status_text: apilevel-O -- title: android.net.wifi.hotspot2 - path: /reference/android/net/wifi/hotspot2/package-summary.html - status_text: apilevel-O -- title: android.net.wifi.hotspot2.omadm - path: /reference/android/net/wifi/hotspot2/omadm/package-summary.html - status_text: apilevel-O -- title: android.net.wifi.hotspot2.pps - path: /reference/android/net/wifi/hotspot2/pps/package-summary.html - status_text: apilevel-O -- title: android.net.wifi.p2p - path: /reference/android/net/wifi/p2p/package-summary.html - status_text: apilevel-14 -- title: android.net.wifi.p2p.nsd - path: /reference/android/net/wifi/p2p/nsd/package-summary.html - status_text: apilevel-16 -- title: android.nfc - path: /reference/android/nfc/package-summary.html - status_text: apilevel-9 -- title: android.nfc.cardemulation - path: /reference/android/nfc/cardemulation/package-summary.html - status_text: apilevel-19 -- title: android.nfc.tech - path: /reference/android/nfc/tech/package-summary.html - status_text: apilevel-10 -- title: android.opengl - path: /reference/android/opengl/package-summary.html - status_text: apilevel-1 -- title: android.os - path: /reference/android/os/package-summary.html - status_text: apilevel-1 -- title: android.os.health - path: /reference/android/os/health/package-summary.html - status_text: apilevel-24 -- title: android.os.storage - path: /reference/android/os/storage/package-summary.html - status_text: apilevel-9 -- title: android.preference - path: /reference/android/preference/package-summary.html - status_text: apilevel-1 -- title: android.print - path: /reference/android/print/package-summary.html - status_text: apilevel-19 -- title: android.print.pdf - path: /reference/android/print/pdf/package-summary.html - status_text: apilevel-19 -- title: android.printservice - path: /reference/android/printservice/package-summary.html - status_text: apilevel-19 -- title: android.provider - path: /reference/android/provider/package-summary.html - status_text: apilevel-1 -- title: android.renderscript - path: /reference/android/renderscript/package-summary.html - status_text: apilevel-11 -- title: android.sax - path: /reference/android/sax/package-summary.html - status_text: apilevel-1 -- title: android.security - path: /reference/android/security/package-summary.html - status_text: apilevel-14 -- title: android.security.keystore - path: /reference/android/security/keystore/package-summary.html - status_text: apilevel-23 -- title: android.service.autofill - path: /reference/android/service/autofill/package-summary.html - status_text: apilevel-O -- title: android.service.carrier - path: /reference/android/service/carrier/package-summary.html - status_text: apilevel-22 -- title: android.service.chooser - path: /reference/android/service/chooser/package-summary.html - status_text: apilevel-23 -- title: android.service.dreams - path: /reference/android/service/dreams/package-summary.html - status_text: apilevel-17 -- title: android.service.media - path: /reference/android/service/media/package-summary.html - status_text: apilevel-21 -- title: android.service.notification - path: /reference/android/service/notification/package-summary.html - status_text: apilevel-18 -- title: android.service.quicksettings - path: /reference/android/service/quicksettings/package-summary.html - status_text: apilevel-24 -- title: android.service.restrictions - path: /reference/android/service/restrictions/package-summary.html - status_text: apilevel-21 -- title: android.service.textservice - path: /reference/android/service/textservice/package-summary.html - status_text: apilevel-14 -- title: android.service.voice - path: /reference/android/service/voice/package-summary.html - status_text: apilevel-21 -- title: android.service.vr - path: /reference/android/service/vr/package-summary.html - status_text: apilevel-24 -- title: android.service.wallpaper - path: /reference/android/service/wallpaper/package-summary.html - status_text: apilevel-7 -- title: android.speech - path: /reference/android/speech/package-summary.html - status_text: apilevel-3 -- title: android.speech.tts - path: /reference/android/speech/tts/package-summary.html - status_text: apilevel-4 -- title: android.support.animation - path: /reference/android/support/animation/package-summary.html - status_text: apilevel-25.3.0 -- title: android.support.annotation - path: /reference/android/support/annotation/package-summary.html - status_text: apilevel- -- title: android.support.app.recommendation - path: /reference/android/support/app/recommendation/package-summary.html - status_text: apilevel-23.0.0 -- title: android.support.compat - path: /reference/android/support/compat/package-summary.html - status_text: apilevel- -- title: android.support.coreui - path: /reference/android/support/coreui/package-summary.html - status_text: apilevel- -- title: android.support.coreutils - path: /reference/android/support/coreutils/package-summary.html - status_text: apilevel- -- title: android.support.customtabs - path: /reference/android/support/customtabs/package-summary.html - status_text: apilevel-23.0.0 -- title: android.support.design - path: /reference/android/support/design/package-summary.html - status_text: apilevel- -- title: android.support.design.widget - path: /reference/android/support/design/widget/package-summary.html - status_text: apilevel-22.2.0 -- title: android.support.dynamicanimation - path: /reference/android/support/dynamicanimation/package-summary.html - status_text: apilevel- -- title: android.support.exifinterface - path: /reference/android/support/exifinterface/package-summary.html - status_text: apilevel- -- title: android.support.fragment - path: /reference/android/support/fragment/package-summary.html - status_text: apilevel- -- title: android.support.graphics.drawable - path: /reference/android/support/graphics/drawable/package-summary.html - status_text: apilevel-23.2.0 -- title: android.support.graphics.drawable.animated - path: /reference/android/support/graphics/drawable/animated/package-summary.html - status_text: apilevel- -- title: android.support.media - path: /reference/android/support/media/package-summary.html - status_text: apilevel-25.1.0 -- title: android.support.media.instantvideo - path: /reference/android/support/media/instantvideo/package-summary.html - status_text: apilevel- -- title: android.support.media.instantvideo.preload - path: /reference/android/support/media/instantvideo/preload/package-summary.html - status_text: apilevel-26.0.0-alpha1 -- title: android.support.media.instantvideo.widget - path: /reference/android/support/media/instantvideo/widget/package-summary.html - status_text: apilevel-26.0.0-alpha1 -- title: android.support.media.tv - path: /reference/android/support/media/tv/package-summary.html - status_text: apilevel-26.0.0-alpha1 -- title: android.support.mediacompat - path: /reference/android/support/mediacompat/package-summary.html - status_text: apilevel- -- title: android.support.multidex - path: /reference/android/support/multidex/package-summary.html - status_text: apilevel- -- title: android.support.percent - path: /reference/android/support/percent/package-summary.html - status_text: apilevel-23.0.0 -- title: android.support.recommendation - path: /reference/android/support/recommendation/package-summary.html - status_text: apilevel- -- title: android.support.transition - path: /reference/android/support/transition/package-summary.html - status_text: apilevel-24.2.0 -- title: android.support.v13 - path: /reference/android/support/v13/package-summary.html - status_text: apilevel- -- title: android.support.v13.app - path: /reference/android/support/v13/app/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v13.view - path: /reference/android/support/v13/view/package-summary.html - status_text: apilevel-24.0.0 -- title: android.support.v13.view.inputmethod - path: /reference/android/support/v13/view/inputmethod/package-summary.html - status_text: apilevel-25.0.0 -- title: android.support.v14.preference - path: /reference/android/support/v14/preference/package-summary.html - status_text: apilevel-23.0.0 -- title: android.support.v17.leanback - path: /reference/android/support/v17/leanback/package-summary.html - status_text: apilevel- -- title: android.support.v17.leanback.app - path: /reference/android/support/v17/leanback/app/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v17.leanback.database - path: /reference/android/support/v17/leanback/database/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v17.leanback.graphics - path: /reference/android/support/v17/leanback/graphics/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v17.leanback.media - path: /reference/android/support/v17/leanback/media/package-summary.html - status_text: apilevel-25.1.0 -- title: android.support.v17.leanback.system - path: /reference/android/support/v17/leanback/system/package-summary.html - status_text: apilevel-22.2.1 -- title: android.support.v17.leanback.widget - path: /reference/android/support/v17/leanback/widget/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v17.leanback.widget.picker - path: /reference/android/support/v17/leanback/widget/picker/package-summary.html - status_text: apilevel-23.2.0 -- title: android.support.v17.preference - path: /reference/android/support/v17/preference/package-summary.html - status_text: apilevel-23.0.0 -- title: android.support.v4 - path: /reference/android/support/v4/package-summary.html - status_text: apilevel- -- title: android.support.v4.accessibilityservice - path: /reference/android/support/v4/accessibilityservice/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.app - path: /reference/android/support/v4/app/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.content - path: /reference/android/support/v4/content/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.content.pm - path: /reference/android/support/v4/content/pm/package-summary.html - status_text: apilevel-22.2.0 -- title: android.support.v4.content.res - path: /reference/android/support/v4/content/res/package-summary.html - status_text: apilevel-22.2.0 -- title: android.support.v4.database - path: /reference/android/support/v4/database/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.graphics - path: /reference/android/support/v4/graphics/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.graphics.drawable - path: /reference/android/support/v4/graphics/drawable/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.hardware.display - path: /reference/android/support/v4/hardware/display/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.hardware.fingerprint - path: /reference/android/support/v4/hardware/fingerprint/package-summary.html - status_text: apilevel-23.0.0 -- title: android.support.v4.math - path: /reference/android/support/v4/math/package-summary.html - status_text: apilevel-26.0.0-alpha1 -- title: android.support.v4.media - path: /reference/android/support/v4/media/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.media.session - path: /reference/android/support/v4/media/session/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.net - path: /reference/android/support/v4/net/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.os - path: /reference/android/support/v4/os/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.print - path: /reference/android/support/v4/print/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.provider - path: /reference/android/support/v4/provider/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.text - path: /reference/android/support/v4/text/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.text.util - path: /reference/android/support/v4/text/util/package-summary.html - status_text: apilevel-24.2.0 -- title: android.support.v4.util - path: /reference/android/support/v4/util/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.view - path: /reference/android/support/v4/view/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.view.accessibility - path: /reference/android/support/v4/view/accessibility/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v4.view.animation - path: /reference/android/support/v4/view/animation/package-summary.html - status_text: apilevel-22.1.0 -- title: android.support.v4.widget - path: /reference/android/support/v4/widget/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v7.app - path: /reference/android/support/v7/app/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v7.appcompat - path: /reference/android/support/v7/appcompat/package-summary.html - status_text: apilevel-22.2.0 -- title: android.support.v7.cardview - path: /reference/android/support/v7/cardview/package-summary.html - status_text: apilevel- -- title: android.support.v7.content.res - path: /reference/android/support/v7/content/res/package-summary.html - status_text: apilevel-24.0.0 -- title: android.support.v7.graphics - path: /reference/android/support/v7/graphics/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v7.graphics.drawable - path: /reference/android/support/v7/graphics/drawable/package-summary.html - status_text: apilevel-23.0.0 -- title: android.support.v7.gridlayout - path: /reference/android/support/v7/gridlayout/package-summary.html - status_text: apilevel- -- title: android.support.v7.media - path: /reference/android/support/v7/media/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v7.mediarouter - path: /reference/android/support/v7/mediarouter/package-summary.html - status_text: apilevel- -- title: android.support.v7.palette - path: /reference/android/support/v7/palette/package-summary.html - status_text: apilevel- -- title: android.support.v7.preference - path: /reference/android/support/v7/preference/package-summary.html - status_text: apilevel-23.0.0 -- title: android.support.v7.recyclerview - path: /reference/android/support/v7/recyclerview/package-summary.html - status_text: apilevel-22.2.0 -- title: android.support.v7.util - path: /reference/android/support/v7/util/package-summary.html - status_text: apilevel-22.1.0 -- title: android.support.v7.view - path: /reference/android/support/v7/view/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v7.widget - path: /reference/android/support/v7/widget/package-summary.html - status_text: apilevel-22.0.0 -- title: android.support.v7.widget.helper - path: /reference/android/support/v7/widget/helper/package-summary.html - status_text: apilevel-22.2.0 -- title: android.support.v7.widget.util - path: /reference/android/support/v7/widget/util/package-summary.html - status_text: apilevel-22.1.0 -- title: android.support.v8.renderscript - path: /reference/android/support/v8/renderscript/package-summary.html - status_text: apilevel-23.0.0 -- title: android.support.wearable - path: /reference/android/support/wearable/package-summary.html - status_text: apilevel- -- title: android.support.wearable.view - path: /reference/android/support/wearable/view/package-summary.html - status_text: apilevel-26.0.0-alpha1 -- title: android.system - path: /reference/android/system/package-summary.html - status_text: apilevel-21 -- title: android.telecom - path: /reference/android/telecom/package-summary.html - status_text: apilevel-21 -- title: android.telephony - path: /reference/android/telephony/package-summary.html - status_text: apilevel-1 -- title: android.telephony.cdma - path: /reference/android/telephony/cdma/package-summary.html - status_text: apilevel-5 -- title: android.telephony.gsm - path: /reference/android/telephony/gsm/package-summary.html - status_text: apilevel-1 -- title: android.test - path: /reference/android/test/package-summary.html - status_text: apilevel-1 -- title: android.test.mock - path: /reference/android/test/mock/package-summary.html - status_text: apilevel-1 -- title: android.test.suitebuilder - path: /reference/android/test/suitebuilder/package-summary.html - status_text: apilevel-1 -- title: android.test.suitebuilder.annotation - path: /reference/android/test/suitebuilder/annotation/package-summary.html - status_text: apilevel-1 -- title: android.text - path: /reference/android/text/package-summary.html - status_text: apilevel-1 -- title: android.text.format - path: /reference/android/text/format/package-summary.html - status_text: apilevel-3 -- title: android.text.method - path: /reference/android/text/method/package-summary.html - status_text: apilevel-1 -- title: android.text.style - path: /reference/android/text/style/package-summary.html - status_text: apilevel-1 -- title: android.text.util - path: /reference/android/text/util/package-summary.html - status_text: apilevel-1 -- title: android.transition - path: /reference/android/transition/package-summary.html - status_text: apilevel-19 -- title: android.util - path: /reference/android/util/package-summary.html - status_text: apilevel-1 -- title: android.view - path: /reference/android/view/package-summary.html - status_text: apilevel-1 -- title: android.view.accessibility - path: /reference/android/view/accessibility/package-summary.html - status_text: apilevel-4 -- title: android.view.animation - path: /reference/android/view/animation/package-summary.html - status_text: apilevel-1 -- title: android.view.autofill - path: /reference/android/view/autofill/package-summary.html - status_text: apilevel-O -- title: android.view.inputmethod - path: /reference/android/view/inputmethod/package-summary.html - status_text: apilevel-3 -- title: android.view.textclassifier - path: /reference/android/view/textclassifier/package-summary.html - status_text: apilevel-O -- title: android.view.textservice - path: /reference/android/view/textservice/package-summary.html - status_text: apilevel-14 -- title: android.webkit - path: /reference/android/webkit/package-summary.html - status_text: apilevel-1 -- title: android.widget - path: /reference/android/widget/package-summary.html - status_text: apilevel-1 -- title: com.android.test.runner - path: /reference/com/android/test/runner/package-summary.html - status_text: apilevel- -- title: dalvik.annotation - path: /reference/dalvik/annotation/package-summary.html - status_text: apilevel-1 -- title: dalvik.bytecode - path: /reference/dalvik/bytecode/package-summary.html - status_text: apilevel-1 -- title: dalvik.system - path: /reference/dalvik/system/package-summary.html - status_text: apilevel-1 -- title: java.awt.font - path: /reference/java/awt/font/package-summary.html - status_text: apilevel-1 -- title: java.beans - path: /reference/java/beans/package-summary.html - status_text: apilevel-3 -- title: java.io - path: /reference/java/io/package-summary.html - status_text: apilevel-1 -- title: java.lang - path: /reference/java/lang/package-summary.html - status_text: apilevel-1 -- title: java.lang.annotation - path: /reference/java/lang/annotation/package-summary.html - status_text: apilevel-1 -- title: java.lang.invoke - path: /reference/java/lang/invoke/package-summary.html - status_text: apilevel-O -- title: java.lang.ref - path: /reference/java/lang/ref/package-summary.html - status_text: apilevel-1 -- title: java.lang.reflect - path: /reference/java/lang/reflect/package-summary.html - status_text: apilevel-1 -- title: java.math - path: /reference/java/math/package-summary.html - status_text: apilevel-1 -- title: java.net - path: /reference/java/net/package-summary.html - status_text: apilevel-1 -- title: java.nio - path: /reference/java/nio/package-summary.html - status_text: apilevel-1 -- title: java.nio.channels - path: /reference/java/nio/channels/package-summary.html - status_text: apilevel-1 -- title: java.nio.channels.spi - path: /reference/java/nio/channels/spi/package-summary.html - status_text: apilevel-1 -- title: java.nio.charset - path: /reference/java/nio/charset/package-summary.html - status_text: apilevel-1 -- title: java.nio.charset.spi - path: /reference/java/nio/charset/spi/package-summary.html - status_text: apilevel-1 -- title: java.nio.file - path: /reference/java/nio/file/package-summary.html - status_text: apilevel-O -- title: java.nio.file.attribute - path: /reference/java/nio/file/attribute/package-summary.html - status_text: apilevel-O -- title: java.nio.file.spi - path: /reference/java/nio/file/spi/package-summary.html - status_text: apilevel-O -- title: java.security - path: /reference/java/security/package-summary.html - status_text: apilevel-1 -- title: java.security.acl - path: /reference/java/security/acl/package-summary.html - status_text: apilevel-1 -- title: java.security.cert - path: /reference/java/security/cert/package-summary.html - status_text: apilevel-1 -- title: java.security.interfaces - path: /reference/java/security/interfaces/package-summary.html - status_text: apilevel-1 -- title: java.security.spec - path: /reference/java/security/spec/package-summary.html - status_text: apilevel-1 -- title: java.sql - path: /reference/java/sql/package-summary.html - status_text: apilevel-1 -- title: java.text - path: /reference/java/text/package-summary.html - status_text: apilevel-1 -- title: java.time - path: /reference/java/time/package-summary.html - status_text: apilevel-O -- title: java.time.chrono - path: /reference/java/time/chrono/package-summary.html - status_text: apilevel-O -- title: java.time.format - path: /reference/java/time/format/package-summary.html - status_text: apilevel-O -- title: java.time.temporal - path: /reference/java/time/temporal/package-summary.html - status_text: apilevel-O -- title: java.time.zone - path: /reference/java/time/zone/package-summary.html - status_text: apilevel-O -- title: java.util - path: /reference/java/util/package-summary.html - status_text: apilevel-1 -- title: java.util.concurrent - path: /reference/java/util/concurrent/package-summary.html - status_text: apilevel-1 -- title: java.util.concurrent.atomic - path: /reference/java/util/concurrent/atomic/package-summary.html - status_text: apilevel-1 -- title: java.util.concurrent.locks - path: /reference/java/util/concurrent/locks/package-summary.html - status_text: apilevel-1 -- title: java.util.function - path: /reference/java/util/function/package-summary.html - status_text: apilevel-24 -- title: java.util.jar - path: /reference/java/util/jar/package-summary.html - status_text: apilevel-1 -- title: java.util.logging - path: /reference/java/util/logging/package-summary.html - status_text: apilevel-1 -- title: java.util.prefs - path: /reference/java/util/prefs/package-summary.html - status_text: apilevel-1 -- title: java.util.regex - path: /reference/java/util/regex/package-summary.html - status_text: apilevel-1 -- title: java.util.stream - path: /reference/java/util/stream/package-summary.html - status_text: apilevel-24 -- title: java.util.zip - path: /reference/java/util/zip/package-summary.html - status_text: apilevel-1 -- title: javax.crypto - path: /reference/javax/crypto/package-summary.html - status_text: apilevel-1 -- title: javax.crypto.interfaces - path: /reference/javax/crypto/interfaces/package-summary.html - status_text: apilevel-1 -- title: javax.crypto.spec - path: /reference/javax/crypto/spec/package-summary.html - status_text: apilevel-1 -- title: javax.microedition.khronos.egl - path: /reference/javax/microedition/khronos/egl/package-summary.html - status_text: apilevel-1 -- title: javax.microedition.khronos.opengles - path: /reference/javax/microedition/khronos/opengles/package-summary.html - status_text: apilevel-1 -- title: javax.net - path: /reference/javax/net/package-summary.html - status_text: apilevel-1 -- title: javax.net.ssl - path: /reference/javax/net/ssl/package-summary.html - status_text: apilevel-1 -- title: javax.security.auth - path: /reference/javax/security/auth/package-summary.html - status_text: apilevel-1 -- title: javax.security.auth.callback - path: /reference/javax/security/auth/callback/package-summary.html - status_text: apilevel-1 -- title: javax.security.auth.login - path: /reference/javax/security/auth/login/package-summary.html - status_text: apilevel-1 -- title: javax.security.auth.x500 - path: /reference/javax/security/auth/x500/package-summary.html - status_text: apilevel-1 -- title: javax.security.cert - path: /reference/javax/security/cert/package-summary.html - status_text: apilevel-1 -- title: javax.sql - path: /reference/javax/sql/package-summary.html - status_text: apilevel-1 -- title: javax.xml - path: /reference/javax/xml/package-summary.html - status_text: apilevel-1 -- title: javax.xml.datatype - path: /reference/javax/xml/datatype/package-summary.html - status_text: apilevel-8 -- title: javax.xml.namespace - path: /reference/javax/xml/namespace/package-summary.html - status_text: apilevel-8 -- title: javax.xml.parsers - path: /reference/javax/xml/parsers/package-summary.html - status_text: apilevel-1 -- title: javax.xml.transform - path: /reference/javax/xml/transform/package-summary.html - status_text: apilevel-8 -- title: javax.xml.transform.dom - path: /reference/javax/xml/transform/dom/package-summary.html - status_text: apilevel-8 -- title: javax.xml.transform.sax - path: /reference/javax/xml/transform/sax/package-summary.html - status_text: apilevel-8 -- title: javax.xml.transform.stream - path: /reference/javax/xml/transform/stream/package-summary.html - status_text: apilevel-8 -- title: javax.xml.validation - path: /reference/javax/xml/validation/package-summary.html - status_text: apilevel-8 -- title: javax.xml.xpath - path: /reference/javax/xml/xpath/package-summary.html - status_text: apilevel-8 -- title: junit.framework - path: /reference/junit/framework/package-summary.html - status_text: apilevel-1 -- title: junit.runner - path: /reference/junit/runner/package-summary.html - status_text: apilevel-1 -- title: org.apache.http.conn - path: /reference/org/apache/http/conn/package-summary.html - status_text: apilevel-1 -- title: org.apache.http.conn.scheme - path: /reference/org/apache/http/conn/scheme/package-summary.html - status_text: apilevel-1 -- title: org.apache.http.conn.ssl - path: /reference/org/apache/http/conn/ssl/package-summary.html - status_text: apilevel-1 -- title: org.apache.http.params - path: /reference/org/apache/http/params/package-summary.html - status_text: apilevel-1 -- title: org.json - path: /reference/org/json/package-summary.html - status_text: apilevel-1 -- title: org.w3c.dom - path: /reference/org/w3c/dom/package-summary.html - status_text: apilevel-1 -- title: org.w3c.dom.ls - path: /reference/org/w3c/dom/ls/package-summary.html - status_text: apilevel-8 -- title: org.xml.sax - path: /reference/org/xml/sax/package-summary.html - status_text: apilevel-1 -- title: org.xml.sax.ext - path: /reference/org/xml/sax/ext/package-summary.html - status_text: apilevel-1 -- title: org.xml.sax.helpers - path: /reference/org/xml/sax/helpers/package-summary.html - status_text: apilevel-1 -- title: org.xmlpull.v1 - path: /reference/org/xmlpull/v1/package-summary.html - status_text: apilevel-1 -- title: org.xmlpull.v1.sax2 - path: /reference/org/xmlpull/v1/sax2/package-summary.html - status_text: apilevel-1 diff --git a/docs/html/reference/_project.yaml b/docs/html/reference/_project.yaml deleted file mode 100644 index e5c26e7fdd8f..000000000000 --- a/docs/html/reference/_project.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: "Reference" -home_url: /reference/ -description: "API Reference packages and classes." -content_license: cc3-apache2 -buganizer_id: 30209417 -parent_project_metadata_path: /develop/_project.yaml diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java index b7699f180281..7234788b2e04 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java @@ -16,15 +16,19 @@ package com.android.settingslib.fuelgauge; +import android.content.ComponentName; +import android.content.Context; import android.content.pm.PackageManager; import android.os.IDeviceIdleController; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.UserHandle; import android.support.annotation.VisibleForTesting; +import android.telecom.DefaultDialerManager; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import com.android.internal.telephony.SmsApplication; import com.android.internal.util.ArrayUtils; /** @@ -38,19 +42,20 @@ public class PowerWhitelistBackend { private static PowerWhitelistBackend sInstance; + private final Context mAppContext; private final IDeviceIdleController mDeviceIdleService; private final ArraySet<String> mWhitelistedApps = new ArraySet<>(); private final ArraySet<String> mSysWhitelistedApps = new ArraySet<>(); private final ArraySet<String> mSysWhitelistedAppsExceptIdle = new ArraySet<>(); - public PowerWhitelistBackend() { - mDeviceIdleService = IDeviceIdleController.Stub.asInterface( - ServiceManager.getService(DEVICE_IDLE_SERVICE)); - refreshList(); + public PowerWhitelistBackend(Context context) { + this(context, IDeviceIdleController.Stub.asInterface( + ServiceManager.getService(DEVICE_IDLE_SERVICE))); } @VisibleForTesting - PowerWhitelistBackend(IDeviceIdleController deviceIdleService) { + PowerWhitelistBackend(Context context, IDeviceIdleController deviceIdleService) { + mAppContext = context.getApplicationContext(); mDeviceIdleService = deviceIdleService; refreshList(); } @@ -64,7 +69,27 @@ public class PowerWhitelistBackend { } public boolean isWhitelisted(String pkg) { - return mWhitelistedApps.contains(pkg); + if (mWhitelistedApps.contains(pkg)) { + return true; + } + + // Additionally, check if pkg is default dialer/sms. They are considered essential apps and + // should be automatically whitelisted (otherwise user may be able to set restriction on + // them, leading to bad device behavior.) + if (!mAppContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { + return false; + } + final ComponentName defaultSms = SmsApplication.getDefaultSmsApplication(mAppContext, + true /* updateIfNeeded */); + if (defaultSms != null && TextUtils.equals(pkg, defaultSms.getPackageName())) { + return true; + } + + final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mAppContext); + if (TextUtils.equals(pkg, defaultDialer)) { + return true; + } + return false; } public boolean isWhitelisted(String[] pkgs) { @@ -120,16 +145,19 @@ public class PowerWhitelistBackend { mSysWhitelistedApps.clear(); mSysWhitelistedAppsExceptIdle.clear(); mWhitelistedApps.clear(); + if (mDeviceIdleService == null) { + return; + } try { - String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist(); + final String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist(); for (String app : whitelistedApps) { mWhitelistedApps.add(app); } - String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist(); + final String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist(); for (String app : sysWhitelistedApps) { mSysWhitelistedApps.add(app); } - String[] sysWhitelistedAppsExceptIdle = + final String[] sysWhitelistedAppsExceptIdle = mDeviceIdleService.getSystemPowerWhitelistExceptIdle(); for (String app : sysWhitelistedAppsExceptIdle) { mSysWhitelistedAppsExceptIdle.add(app); @@ -139,9 +167,9 @@ public class PowerWhitelistBackend { } } - public static PowerWhitelistBackend getInstance() { + public static PowerWhitelistBackend getInstance(Context context) { if (sInstance == null) { - sInstance = new PowerWhitelistBackend(); + sInstance = new PowerWhitelistBackend(context); } return sInstance; } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java index 0af2c05a6f10..a23eebcce797 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java @@ -23,35 +23,52 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; import android.os.IDeviceIdleController; import com.android.settingslib.SettingsLibRobolectricTestRunner; +import com.android.settingslib.testutils.shadow.ShadowDefaultDialerManager; +import com.android.settingslib.testutils.shadow.ShadowSmsApplication; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowPackageManager; @RunWith(SettingsLibRobolectricTestRunner.class) +@Config(shadows = {ShadowDefaultDialerManager.class, ShadowSmsApplication.class}) public class PowerWhitelistBackendTest { private static final String PACKAGE_ONE = "com.example.packageone"; private static final String PACKAGE_TWO = "com.example.packagetwo"; - private PowerWhitelistBackend mPowerWhitelistBackend; @Mock private IDeviceIdleController mDeviceIdleService; + private PowerWhitelistBackend mPowerWhitelistBackend; + private ShadowPackageManager mPackageManager; + private Context mContext; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist(); doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist(); doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle(); doNothing().when(mDeviceIdleService).addPowerSaveWhitelistApp(anyString()); doNothing().when(mDeviceIdleService).removePowerSaveWhitelistApp(anyString()); - mPowerWhitelistBackend = new PowerWhitelistBackend(mDeviceIdleService); + mPackageManager = Shadow.extract(mContext.getPackageManager()); + mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true); + + mPowerWhitelistBackend = new PowerWhitelistBackend(mContext, mDeviceIdleService); } @Test @@ -61,8 +78,8 @@ public class PowerWhitelistBackendTest { assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue(); assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse(); - assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_ONE})).isTrue(); - assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_TWO})).isFalse(); + assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue(); + assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse(); mPowerWhitelistBackend.addApp(PACKAGE_TWO); @@ -70,15 +87,15 @@ public class PowerWhitelistBackendTest { assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue(); assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isTrue(); assertThat(mPowerWhitelistBackend.isWhitelisted( - new String[]{PACKAGE_ONE, PACKAGE_TWO})).isTrue(); + new String[] {PACKAGE_ONE, PACKAGE_TWO})).isTrue(); mPowerWhitelistBackend.removeApp(PACKAGE_TWO); verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_TWO); assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue(); assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse(); - assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_ONE})).isTrue(); - assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_TWO})).isFalse(); + assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue(); + assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse(); mPowerWhitelistBackend.removeApp(PACKAGE_ONE); @@ -86,7 +103,23 @@ public class PowerWhitelistBackendTest { assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse(); assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse(); assertThat(mPowerWhitelistBackend.isWhitelisted( - new String[]{PACKAGE_ONE, PACKAGE_TWO})).isFalse(); + new String[] {PACKAGE_ONE, PACKAGE_TWO})).isFalse(); + } + + @Test + public void isWhitelisted_shouldWhitelistDefaultSms() { + final String testSms = "com.android.test.defaultsms"; + ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver")); + + assertThat(mPowerWhitelistBackend.isWhitelisted(testSms)).isTrue(); + } + + @Test + public void isWhitelisted_shouldWhitelistDefaultDialer() { + final String testDialer = "com.android.test.defaultdialer"; + ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer); + + assertThat(mPowerWhitelistBackend.isWhitelisted(testDialer)).isTrue(); } @Test @@ -101,7 +134,7 @@ public class PowerWhitelistBackendTest { @Test public void testIsSystemWhitelistedExceptIdle_onePackage() throws Exception { - doReturn(new String[]{PACKAGE_TWO}).when( + doReturn(new String[] {PACKAGE_TWO}).when( mDeviceIdleService).getSystemPowerWhitelistExceptIdle(); mPowerWhitelistBackend.refreshList(); @@ -111,7 +144,7 @@ public class PowerWhitelistBackendTest { @Test public void testIsSystemWhitelistedExceptIdle_packageArray() throws Exception { - doReturn(new String[]{PACKAGE_TWO}).when( + doReturn(new String[] {PACKAGE_TWO}).when( mDeviceIdleService).getSystemPowerWhitelistExceptIdle(); mPowerWhitelistBackend.refreshList(); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java new file mode 100644 index 000000000000..f4afdb11ff95 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 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.settingslib.testutils.shadow; + +import android.content.Context; +import android.telecom.DefaultDialerManager; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.annotation.Resetter; + +@Implements(DefaultDialerManager.class) +public class ShadowDefaultDialerManager { + + private static String sDefaultDailer; + + @Resetter + public void reset() { + sDefaultDailer = null; + } + + @Implementation + public static String getDefaultDialerApplication(Context context) { + return sDefaultDailer; + } + + public static void setDefaultDialerApplication(String dialer) { + sDefaultDailer = dialer; + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java new file mode 100644 index 000000000000..dd7b007ca30b --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018 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.settingslib.testutils.shadow; + +import android.content.ComponentName; +import android.content.Context; + +import com.android.internal.telephony.SmsApplication; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.annotation.Resetter; + +@Implements(SmsApplication.class) +public class ShadowSmsApplication { + + private static ComponentName sDefaultSmsApplication; + + @Resetter + public void reset() { + sDefaultSmsApplication = null; + } + + @Implementation + public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) { + return sDefaultSmsApplication; + } + + public static void setDefaultSmsApplication(ComponentName cn) { + sDefaultSmsApplication = cn; + } +}
\ No newline at end of file diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 28e8db9e488b..e1a602b53d9d 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -214,4 +214,7 @@ <!-- Default for Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS --> <string name="def_backup_agent_timeout_parameters"></string> + + <!-- Default for Settings.System.VIBRATE_WHEN_RINGING --> + <bool name="def_vibrate_when_ringing">false</bool> </resources> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index fbe52d191c30..960d30524b95 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -2935,7 +2935,7 @@ public class SettingsProvider extends ContentProvider { } private final class UpgradeController { - private static final int SETTINGS_VERSION = 168; + private static final int SETTINGS_VERSION = 169; private final int mUserId; @@ -3805,6 +3805,21 @@ public class SettingsProvider extends ContentProvider { currentVersion = 168; } + if (currentVersion == 168) { + // Version 168: by default, vibrate for phone calls + final SettingsState systemSettings = getSystemSettingsLocked(userId); + final Setting currentSetting = systemSettings.getSettingLocked( + Settings.System.VIBRATE_WHEN_RINGING); + if (currentSetting.isNull()) { + systemSettings.insertSettingLocked( + Settings.System.VIBRATE_WHEN_RINGING, + getContext().getResources().getBoolean( + R.bool.def_vibrate_when_ringing) ? "1" : "0", + null, true, SettingsState.SYSTEM_PACKAGE_NAME); + } + currentVersion = 169; + } + // vXXX: Add new settings above this point. if (currentVersion != newVersion) { diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 89f9e1f8eabb..9a3bdf271dc0 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -867,6 +867,8 @@ <!-- The size of corner radius of the arrow in the onboarding toast. --> <dimen name="recents_onboarding_toast_arrow_corner_radius">2dp</dimen> + <!-- The start margin of quick scrub onboarding toast. --> + <dimen name="recents_quick_scrub_onboarding_margin_start">8dp</dimen> <!-- The min alpha to apply to a task affiliation group color. --> <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item> diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index 31d8cbb5d19d..ad841308cb0d 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -225,9 +225,10 @@ public class PipMotionHelper implements Handler.Callback { */ boolean shouldDismissPip() { Point displaySize = new Point(); - mContext.getDisplay().getSize(displaySize); - if (mBounds.bottom > displaySize.y) { - float offscreenFraction = (float) (mBounds.bottom - displaySize.y) / mBounds.height(); + mContext.getDisplay().getRealSize(displaySize); + final int y = displaySize.y - mStableInsets.bottom; + if (mBounds.bottom > y) { + float offscreenFraction = (float) (mBounds.bottom - y) / mBounds.height(); return offscreenFraction >= DISMISS_OFFSCREEN_FRACTION; } return false; diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index 8cfba2cc53d7..ab822696d382 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -184,9 +184,15 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { return; } boolean selected = mLastExpansion == 1f; + + // Disable accessibility temporarily while we update selected state purely for the + // marquee. This will ensure that accessibility doesn't announce the TYPE_VIEW_SELECTED + // event on any of the children. + setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); for (int i = 0; i < mPages.size(); i++) { mPages.get(i).setSelected(i == getCurrentItem() ? selected : false); } + setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); } public void setPageListener(PageListener listener) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java index 086c87ba10a5..8d8e20669a1f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java @@ -393,7 +393,20 @@ public class RecentsOnboarding { if (!mLayoutAttachedToWindow && orientation == Configuration.ORIENTATION_PORTRAIT) { mLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); - mWindowManager.addView(mLayout, getWindowLayoutParams()); + final int gravity; + final int x; + if (stringRes == R.string.recents_swipe_up_onboarding) { + gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + x = 0; + } else { + int layoutDirection = + mContext.getResources().getConfiguration().getLayoutDirection(); + gravity = Gravity.BOTTOM | (layoutDirection == View.LAYOUT_DIRECTION_LTR + ? Gravity.LEFT : Gravity.RIGHT); + x = mContext.getResources().getDimensionPixelSize( + R.dimen.recents_quick_scrub_onboarding_margin_start); + } + mWindowManager.addView(mLayout, getWindowLayoutParams(gravity, x)); mLayout.setAlpha(0); mLayout.animate() .alpha(1f) @@ -459,19 +472,19 @@ public class RecentsOnboarding { pw.println(" }"); } - private WindowManager.LayoutParams getWindowLayoutParams() { + private WindowManager.LayoutParams getWindowLayoutParams(int gravity, int x) { int flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, - 0, -mNavBarHeight / 2, + ViewGroup.LayoutParams.WRAP_CONTENT, + x, -mNavBarHeight / 2, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, flags, PixelFormat.TRANSLUCENT); lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; lp.setTitle("RecentsOnboarding"); - lp.gravity = Gravity.BOTTOM; + lp.gravity = gravity; return lp; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java index 03791c7f91ea..91a4dda5a281 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java @@ -182,6 +182,9 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp } } if (mReplyAction != null) { + // Let's reset the view on update, assuming the new pending intent isn't cancelled + // anymore. The color filter automatically resets when it's updated. + mReplyAction.setEnabled(true); performOnPendingIntentCancellation(mReplyAction, () -> { if (mReplyAction != null && mReplyAction.isEnabled()) { mReplyAction.setEnabled(false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java index 8ede2246301b..879ac92b95d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java @@ -16,11 +16,8 @@ package com.android.systemui.statusbar.notification; -import android.util.ArraySet; import android.util.Pools; import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; import android.view.animation.Interpolator; import android.widget.ImageView; import android.widget.ProgressBar; @@ -411,7 +408,8 @@ public class TransformState { mOwnPosition[1] -= (1.0f - mTransformedView.getScaleY()) * mTransformedView.getPivotY(); // Remove local translations - mOwnPosition[1] -= MessagingPropertyAnimator.getLocalTranslationY(mTransformedView); + mOwnPosition[1] -= MessagingPropertyAnimator.getTop(mTransformedView) + - MessagingPropertyAnimator.getLayoutTop(mTransformedView); return mOwnPosition; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java index 3c0b22660c17..894ea62b1b61 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java @@ -114,6 +114,10 @@ public class ButtonDispatcher { return mVisibility != null ? mVisibility : View.VISIBLE; } + public boolean isVisible() { + return getVisibility() == View.VISIBLE; + } + public float getAlpha() { return mAlpha != null ? mAlpha : 1; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 6c66cabf0da8..0fd8df09eaaa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -336,13 +336,14 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav int x = (int) event.getX(); int y = (int) event.getY(); mDownHitTarget = HIT_TARGET_NONE; - if (mBackButtonBounds.contains(x, y)) { + if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) { mDownHitTarget = HIT_TARGET_BACK; - } else if (mHomeButtonBounds.contains(x, y)) { + } else if (getHomeButton().isVisible() && mHomeButtonBounds.contains(x, y)) { mDownHitTarget = HIT_TARGET_HOME; - } else if (mRecentsButtonBounds.contains(x, y)) { + } else if (getRecentsButton().isVisible() && mRecentsButtonBounds.contains(x, y)) { mDownHitTarget = HIT_TARGET_OVERVIEW; - } else if (mRotationButtonBounds.contains(x, y)) { + } else if (getRotateSuggestionButton().isVisible() + && mRotationButtonBounds.contains(x, y)) { mDownHitTarget = HIT_TARGET_ROTATION; } break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 5f5d12e73f66..5001d4ffa13c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -173,11 +173,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb || mStatusBar.isFullScreenUserSwitcherState()) { mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE); } else if (mShowing && !mDozing) { - mBouncer.setExpansion(expansion); + if (!isWakeAndUnlocking()) { + mBouncer.setExpansion(expansion); + } if (expansion != KeyguardBouncer.EXPANSION_HIDDEN && tracking && mStatusBar.isKeyguardCurrentlySecure() && !mBouncer.isShowing() && !mBouncer.isAnimatingAway()) { - mBouncer.show(false /* resetSecuritySelection */, false /* animated */); + mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 7410069b09fa..804fd4161500 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -388,6 +388,7 @@ public class NotificationStackScrollLayout extends ViewGroup return object.getDarkAmount(); } }; + private ObjectAnimator mDarkAmountAnimator; private boolean mUsingLightTheme; private boolean mQsExpanded; private boolean mForwardScrollable; @@ -3401,7 +3402,7 @@ public class NotificationStackScrollLayout extends ViewGroup .animateY(mShelf)); ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex; mAnimationEvents.add(ev); - startBackgroundFade(); + startDarkAmountAnimation(); } mDarkNeedsAnimation = false; } @@ -3979,6 +3980,9 @@ public class NotificationStackScrollLayout extends ViewGroup mDarkAnimationOriginIndex = findDarkAnimationOriginIndex(touchWakeUpScreenLocation); mNeedsAnimation = true; } else { + if (mDarkAmountAnimator != null) { + mDarkAmountAnimator.cancel(); + } setDarkAmount(dark ? 1f : 0f); updateBackground(); } @@ -4023,12 +4027,22 @@ public class NotificationStackScrollLayout extends ViewGroup return mDarkAmount; } - private void startBackgroundFade() { - ObjectAnimator fadeAnimator = ObjectAnimator.ofFloat(this, DARK_AMOUNT, mDarkAmount, + private void startDarkAmountAnimation() { + ObjectAnimator darkAnimator = ObjectAnimator.ofFloat(this, DARK_AMOUNT, mDarkAmount, mAmbientState.isDark() ? 1f : 0); - fadeAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP); - fadeAnimator.setInterpolator(Interpolators.ALPHA_IN); - fadeAnimator.start(); + darkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP); + darkAnimator.setInterpolator(Interpolators.ALPHA_IN); + darkAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mDarkAmountAnimator = null; + } + }); + if (mDarkAmountAnimator != null) { + mDarkAmountAnimator.cancel(); + } + mDarkAmountAnimator = darkAnimator; + mDarkAmountAnimator.start(); } private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 8340ab2e7935..85135ac77b3c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -16,14 +16,12 @@ package com.android.systemui.statusbar.phone; -import static com.google.common.truth.Truth.assertThat; - import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.content.Context; @@ -170,6 +168,15 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { verify(mBouncer, never()).setExpansion(eq(0.5f)); } + @Test + public void onPanelExpansionChanged_neverTranslatesBouncerWhenWakeAndUnlock() { + when(mFingerprintUnlockController.getMode()) + .thenReturn(FingerprintUnlockController.MODE_WAKE_AND_UNLOCK); + mStatusBarKeyguardViewManager.onPanelExpansionChanged(KeyguardBouncer.EXPANSION_VISIBLE, + false /* tracking */); + verify(mBouncer, never()).setExpansion(anyFloat()); + } + private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager { public TestableStatusBarKeyguardViewManager(Context context, diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 3beebcba6c5d..aa86ea8b03e2 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -812,11 +812,12 @@ public class AppOpsService extends IAppOpsService.Stub { resOps = new ArrayList<>(); for (int j=0; j<pkgOps.size(); j++) { Op curOp = pkgOps.valueAt(j); - long duration = curOp.duration == -1 + final boolean running = curOp.duration == -1; + long duration = running ? (elapsedNow - curOp.startRealtime) : curOp.duration; resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time, - curOp.rejectTime, (int) duration, curOp.proxyUid, + curOp.rejectTime, (int) duration, running, curOp.proxyUid, curOp.proxyPackageName)); } } else { @@ -826,11 +827,12 @@ public class AppOpsService extends IAppOpsService.Stub { if (resOps == null) { resOps = new ArrayList<>(); } - long duration = curOp.duration == -1 + final boolean running = curOp.duration == -1; + final long duration = running ? (elapsedNow - curOp.startRealtime) : curOp.duration; resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time, - curOp.rejectTime, (int) duration, curOp.proxyUid, + curOp.rejectTime, (int) duration, running, curOp.proxyUid, curOp.proxyPackageName)); } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 4c2a94092e23..ca715b51a328 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -119,7 +119,7 @@ public final class ActiveServices { // How long the startForegroundService() grace period is to get around to // calling startForeground() before we ANR + stop it. - static final int SERVICE_START_FOREGROUND_TIMEOUT = 5*1000; + static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000; final ActivityManagerService mAm; @@ -501,6 +501,18 @@ public final class ActiveServices { } } + // At this point we've applied allowed-to-start policy based on whether this was + // an ordinary startService() or a startForegroundService(). Now, only require that + // the app follow through on the startForegroundService() -> startForeground() + // contract if it actually targets O+. + if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) { + if (DEBUG_BACKGROUND_CHECK || DEBUG_FOREGROUND_SERVICE) { + Slog.i(TAG, "startForegroundService() but host targets " + + r.appInfo.targetSdkVersion + " - not requiring startForeground()"); + } + fgRequired = false; + } + NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked( callingUid, r.packageName, service, service.getFlags(), null, r.userId); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 16f4585c6095..d456f6255426 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -2413,11 +2413,16 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } // Compute configuration based on max supported width and height. - outBounds.set(0, 0, maxActivityWidth, maxActivityHeight); - // Position the activity frame on the opposite side of the nav bar. - final int navBarPosition = service.mWindowManager.getNavBarPosition(); - final int left = navBarPosition == NAV_BAR_LEFT ? appBounds.right - outBounds.width() : 0; - outBounds.offsetTo(left, 0 /* top */); + // Also account for the left / top insets (e.g. from display cutouts), which will be clipped + // away later in StackWindowController.adjustConfigurationForBounds(). Otherwise, the app + // bounds would end up too small. + outBounds.set(0, 0, maxActivityWidth + appBounds.left, maxActivityHeight + appBounds.top); + + if (service.mWindowManager.getNavBarPosition() == NAV_BAR_LEFT) { + // Position the activity frame on the opposite side of the nav bar. + outBounds.left = appBounds.right - maxActivityWidth; + outBounds.right = appBounds.right; + } } boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 28665e3c3942..92310b92d932 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -3299,6 +3299,9 @@ public class AudioService extends IAudioService.Stub .append(Binder.getCallingPid()).toString(); synchronized (mBluetoothA2dpEnabledLock) { + if (mBluetoothA2dpEnabled == on) { + return; + } mBluetoothA2dpEnabled = on; sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE, AudioSystem.FOR_MEDIA, diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 4e6307dbca8a..0f8c5269a95c 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -1015,26 +1015,25 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt locationListener = mFusedLocationListener; } - if (!locationManager.isProviderEnabled(provider)) { - Log.w(TAG, "Unable to request location since " + provider - + " provider does not exist or is not enabled."); - return; - } - Log.i(TAG, String.format( "GNSS HAL Requesting location updates from %s provider for %d millis.", provider, durationMillis)); - locationManager.requestLocationUpdates(provider, - LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0, - locationListener, mHandler.getLooper()); - locationListener.numLocationUpdateRequest++; - mHandler.postDelayed(() -> { - if (--locationListener.numLocationUpdateRequest == 0) { - Log.i(TAG, String.format("Removing location updates from %s provider.", provider)); - locationManager.removeUpdates(locationListener); - } - }, durationMillis); + try { + locationManager.requestLocationUpdates(provider, + LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0, + locationListener, mHandler.getLooper()); + locationListener.numLocationUpdateRequest++; + mHandler.postDelayed(() -> { + if (--locationListener.numLocationUpdateRequest == 0) { + Log.i(TAG, + String.format("Removing location updates from %s provider.", provider)); + locationManager.removeUpdates(locationListener); + } + }, durationMillis); + } catch (IllegalArgumentException e) { + Log.w(TAG, "Unable to request location.", e); + } } private void injectBestLocation(Location location) { diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 384efdda88d7..a7df0e23f63b 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -95,9 +95,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub // State guarded by mLock. private final Object mLock = new Object(); - private final SparseArray<UserRecord> mUserRecords = new SparseArray<UserRecord>(); - private final ArrayMap<IBinder, ClientRecord> mAllClientRecords = - new ArrayMap<IBinder, ClientRecord>(); + private final SparseArray<UserRecord> mUserRecords = new SparseArray<>(); + private final ArrayMap<IBinder, ClientRecord> mAllClientRecords = new ArrayMap<>(); private int mCurrentUserId = -1; private final IAudioService mAudioService; private final AudioPlayerStateMonitor mAudioPlayerStateMonitor; @@ -106,7 +105,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub private final IntArray mActivePlayerUidMinPriorityQueue = new IntArray(); private final BroadcastReceiver mReceiver = new MediaRouterServiceBroadcastReceiver(); - BluetoothDevice mBluetoothDevice; + BluetoothDevice mActiveBluetoothDevice; int mAudioRouteMainType = AudioRoutesInfo.MAIN_SPEAKER; boolean mGlobalBluetoothA2dpOn = false; @@ -180,7 +179,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub | AudioRoutesInfo.MAIN_HEADPHONES | AudioRoutesInfo.MAIN_USB)) == 0) { // headset was plugged out. - mGlobalBluetoothA2dpOn = mBluetoothDevice != null; + mGlobalBluetoothA2dpOn = (newRoutes.bluetoothName != null + || mActiveBluetoothDevice != null); } else { // headset was plugged in. mGlobalBluetoothA2dpOn = false; @@ -197,7 +197,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub Slog.w(TAG, "RemoteException in the audio service."); } - IntentFilter intentFilter = new IntentFilter(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); + IntentFilter intentFilter = new IntentFilter(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED); context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null); } @@ -406,12 +406,14 @@ public final class MediaRouterService extends IMediaRouterService.Stub void restoreBluetoothA2dp() { try { - boolean a2dpOn = false; + boolean a2dpOn; + BluetoothDevice btDevice; synchronized (mLock) { a2dpOn = mGlobalBluetoothA2dpOn; + btDevice = mActiveBluetoothDevice; } // We don't need to change a2dp status when bluetooth is not connected. - if (mBluetoothDevice != null) { + if (btDevice != null) { Slog.v(TAG, "restoreBluetoothA2dp(" + a2dpOn + ")"); mAudioService.setBluetoothA2dpOn(a2dpOn); } @@ -653,17 +655,11 @@ public final class MediaRouterService extends IMediaRouterService.Stub final class MediaRouterServiceBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) { - int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, - BluetoothProfile.STATE_DISCONNECTED); - if (state == BluetoothProfile.STATE_DISCONNECTED) { - mGlobalBluetoothA2dpOn = false; - mBluetoothDevice = null; - } else if (state == BluetoothProfile.STATE_CONNECTED) { - mGlobalBluetoothA2dpOn = true; - mBluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - // To ensure that BT A2DP is on, call restoreBluetoothA2dp(). - restoreBluetoothA2dp(); + if (intent.getAction().equals(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED)) { + BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + synchronized (mLock) { + mActiveBluetoothDevice = btDevice; + mGlobalBluetoothA2dpOn = btDevice != null; } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e810b1adaac3..d496ab67fec4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -17260,17 +17260,6 @@ public class PackageManagerService extends IPackageManager.Stub + "Persistent apps are not updateable."); return; } - // Prevent apps from downgrading their targetSandbox. - final int oldTargetSandbox = oldPackage.applicationInfo.targetSandboxVersion; - final int newTargetSandbox = pkg.applicationInfo.targetSandboxVersion; - if (oldTargetSandbox == 2 && newTargetSandbox != 2) { - res.setError(PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE, - "Package " + pkg.packageName + " new target sandbox " - + newTargetSandbox + " is incompatible with the previous value of" - + oldTargetSandbox + "."); - return; - } - // Prevent installing of child packages if (oldPackage.parentPackage != null) { res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java index 91ef3d4a576e..ed2b79e7380c 100644 --- a/services/core/java/com/android/server/power/BatterySaverPolicy.java +++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java @@ -392,7 +392,7 @@ public class BatterySaverPolicy extends ContentObserver { mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true); mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true); mAodDisabled = parser.getBoolean(KEY_AOD_DISABLED, true); - mSendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, true); + mSendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, false); // Get default value from Settings.Secure final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE, diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java index b8431b1d8ad8..65c8e96a0774 100644 --- a/services/core/java/com/android/server/wm/Dimmer.java +++ b/services/core/java/com/android/server/wm/Dimmer.java @@ -22,7 +22,9 @@ import static com.android.server.wm.AlphaAnimationSpecProto.TO; import static com.android.server.wm.AnimationSpecProto.ALPHA; import android.graphics.Rect; +import android.util.Log; import android.util.proto.ProtoOutputStream; +import android.view.Surface; import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; @@ -171,14 +173,18 @@ class Dimmer { */ private DimState getDimState(WindowContainer container) { if (mDimState == null) { - final SurfaceControl ctl = makeDimLayer(); - mDimState = new DimState(ctl); - /** - * See documentation on {@link #dimAbove} to understand lifecycle management of Dim's - * via state resetting for Dim's with containers. - */ - if (container == null) { - mDimState.mDontReset = true; + try { + final SurfaceControl ctl = makeDimLayer(); + mDimState = new DimState(ctl); + /** + * See documentation on {@link #dimAbove} to understand lifecycle management of + * Dim's via state resetting for Dim's with containers. + */ + if (container == null) { + mDimState.mDontReset = true; + } + } catch (Surface.OutOfResourcesException e) { + Log.w(TAG, "OutOfResourcesException creating dim surface"); } } @@ -189,6 +195,11 @@ class Dimmer { private void dim(SurfaceControl.Transaction t, WindowContainer container, int relativeLayer, float alpha) { final DimState d = getDimState(container); + + if (d == null) { + return; + } + if (container != null) { // The dim method is called from WindowState.prepareSurfaces(), which is always called // in the correct Z from lowest Z to highest. This ensures that the dim layer is always @@ -208,10 +219,11 @@ class Dimmer { * @param t A Transaction in which to finish the dim. */ void stopDim(SurfaceControl.Transaction t) { - DimState d = getDimState(null); - t.hide(d.mDimLayer); - d.isVisible = false; - d.mDontReset = false; + if (mDimState != null) { + t.hide(mDimState.mDimLayer); + mDimState.isVisible = false; + mDimState.mDontReset = false; + } } /** diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java index 7211533c1b44..2bfff269e457 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java @@ -206,6 +206,9 @@ class SurfaceAnimationRunner { } } }); + a.mAnim = anim; + mRunningAnimations.put(a.mLeash, a); + anim.start(); if (a.mAnimSpec.canSkipFirstFrame()) { // If we can skip the first frame, we start one frame later. @@ -215,8 +218,6 @@ class SurfaceAnimationRunner { // Immediately start the animation by manually applying an animation frame. Otherwise, the // start time would only be set in the next frame, leading to a delay. anim.doAnimationFrame(mChoreographer.getFrameTime()); - a.mAnim = anim; - mRunningAnimations.put(a.mLeash, a); } private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) { diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java index c366e4d6108b..7b775f568292 100644 --- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java +++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java @@ -54,7 +54,7 @@ public class WindowManagerDebugConfig { static final boolean DEBUG_STARTING_WINDOW_VERBOSE = false; static final boolean DEBUG_STARTING_WINDOW = DEBUG_STARTING_WINDOW_VERBOSE || false; static final boolean DEBUG_WALLPAPER = false; - static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER; + static final boolean DEBUG_WALLPAPER_LIGHT = true || DEBUG_WALLPAPER; static final boolean DEBUG_DRAG = false; static final boolean DEBUG_SCREEN_ON = false; static final boolean DEBUG_SCREENSHOT = false; diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java b/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java index ea0fe455672b..7f397d6a2cfc 100644 --- a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java +++ b/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java @@ -18,6 +18,8 @@ package com.android.server.appops; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; @@ -36,6 +38,8 @@ import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.List; + /** * Tests app ops version upgrades */ @@ -107,6 +111,46 @@ public class AppOpsActiveWatcherTest { verifyNoMoreInteractions(listener); } + @Test + public void testIsRunning() throws Exception { + final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); + // Start the op + appOpsManager.startOp(AppOpsManager.OP_CAMERA); + + assertTrue("Camera should be running", isCameraOn(appOpsManager)); + + // Finish the op + appOpsManager.finishOp(AppOpsManager.OP_CAMERA); + + assertFalse("Camera should not be running", isCameraOn(appOpsManager)); + } + + private boolean isCameraOn(AppOpsManager appOpsManager) { + List<AppOpsManager.PackageOps> packages + = appOpsManager.getPackagesForOps(new int[] {AppOpsManager.OP_CAMERA}); + // AppOpsManager can return null when there is no requested data. + if (packages != null) { + final int numPackages = packages.size(); + for (int packageInd = 0; packageInd < numPackages; packageInd++) { + AppOpsManager.PackageOps packageOp = packages.get(packageInd); + List<AppOpsManager.OpEntry> opEntries = packageOp.getOps(); + if (opEntries != null) { + final int numOps = opEntries.size(); + for (int opInd = 0; opInd < numOps; opInd++) { + AppOpsManager.OpEntry opEntry = opEntries.get(opInd); + if (opEntry.getOp() == AppOpsManager.OP_CAMERA) { + if (opEntry.isRunning()) { + return true; + } + } + } + } + } + } + + return false; + } + private static Context getContext() { return InstrumentationRegistry.getContext(); } |