diff options
29 files changed, 579 insertions, 175 deletions
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index c2ee21d5115d..7c34ddcb9287 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -878,7 +878,7 @@ public class InputMethodService extends AbstractInputMethodService { } private void notifyImeHidden() { - doHideWindow(); + requestHideSelf(0); } private void removeImeSurface() { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a28ea899694c..ccc3132c535d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10338,6 +10338,14 @@ public final class Settings { public static final String WIFI_WAKEUP_ENABLED = "wifi_wakeup_enabled"; /** + * Value to specify if wifi settings migration is complete or not. + * + * Type: int (0 for false, 1 for true) + * @hide + */ + public static final String WIFI_MIGRATION_COMPLETED = "wifi_migration_completed"; + + /** * Value to specify whether network quality scores and badging should be shown in the UI. * * Type: int (0 for false, 1 for true) diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java index 9a555c161300..2c260f6b8cbe 100644 --- a/core/java/android/util/proto/ProtoOutputStream.java +++ b/core/java/android/util/proto/ProtoOutputStream.java @@ -201,7 +201,9 @@ public final class ProtoOutputStream extends ProtoStream { } /** - * Returns the uncompressed buffer size + * Returns the total size of the data that has been written, after full + * protobuf encoding has occurred. + * * @return the uncompressed buffer size */ public int getRawSize() { @@ -2271,9 +2273,12 @@ public final class ProtoOutputStream extends ProtoStream { } /** - * Write a field tag to the stream. + * Write an individual field tag by hand. + * + * @see See <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> for details on the structure of how tags and data are written. */ - public void writeTag(int id, int wireType) { + public void writeTag(int id, @WireType int wireType) { mBuffer.writeRawVarint32((id << FIELD_ID_SHIFT) | wireType); } diff --git a/core/java/android/util/proto/ProtoStream.java b/core/java/android/util/proto/ProtoStream.java index 4969d8a7fbe7..1940da907973 100644 --- a/core/java/android/util/proto/ProtoStream.java +++ b/core/java/android/util/proto/ProtoStream.java @@ -16,9 +16,14 @@ package android.util.proto; +import android.annotation.IntDef; +import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Base utility class for protobuf streams. * @@ -30,6 +35,71 @@ import android.annotation.Nullable; public class ProtoStream { /** + * A protobuf wire type. All application-level types are represented using + * varint, fixed64, length-delimited and fixed32 wire types. The start-group + * and end-group types are unused in modern protobuf versions (proto2 and proto3), + * but are included here for completeness. + * + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + WIRE_TYPE_VARINT, + WIRE_TYPE_FIXED64, + WIRE_TYPE_LENGTH_DELIMITED, + WIRE_TYPE_START_GROUP, + WIRE_TYPE_END_GROUP, + WIRE_TYPE_FIXED32 + }) + public @interface WireType {} + + /** + * Application-level protobuf field types, as would be used in a .proto file. + * + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ + @Retention(RetentionPolicy.SOURCE) + @LongDef({ + FIELD_TYPE_UNKNOWN, + FIELD_TYPE_DOUBLE, + FIELD_TYPE_FLOAT, + FIELD_TYPE_INT64, + FIELD_TYPE_UINT64, + FIELD_TYPE_INT32, + FIELD_TYPE_FIXED64, + FIELD_TYPE_FIXED32, + FIELD_TYPE_BOOL, + FIELD_TYPE_STRING, + FIELD_TYPE_MESSAGE, + FIELD_TYPE_BYTES, + FIELD_TYPE_UINT32, + FIELD_TYPE_ENUM, + FIELD_TYPE_SFIXED32, + FIELD_TYPE_SFIXED64, + FIELD_TYPE_SINT32, + FIELD_TYPE_SINT64, + }) + public @interface FieldType {} + + + /** + * Represents the cardinality of a protobuf field. + * + * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf + * Encoding</a> + */ + @Retention(RetentionPolicy.SOURCE) + @LongDef({ + FIELD_COUNT_UNKNOWN, + FIELD_COUNT_SINGLE, + FIELD_COUNT_REPEATED, + FIELD_COUNT_PACKED, + }) + public @interface FieldCount {} + + /** * Number of bits to shift the field number to form a tag. * * <pre> @@ -128,7 +198,7 @@ public class ProtoStream { public static final long FIELD_TYPE_MASK = 0x0ffL << FIELD_TYPE_SHIFT; /** - * Not a real wire type. + * Not a real field type. * @hide */ public static final long FIELD_TYPE_UNKNOWN = 0; @@ -378,7 +448,7 @@ public class ProtoStream { /** * Get the developer-usable name of a field type. */ - public static @Nullable String getFieldTypeString(long fieldType) { + public static @Nullable String getFieldTypeString(@FieldType long fieldType) { int index = ((int) ((fieldType & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) - 1; if (index >= 0 && index < FIELD_TYPE_NAMES.length) { return FIELD_TYPE_NAMES[index]; @@ -405,7 +475,7 @@ public class ProtoStream { /** * Get the developer-usable name of a wire type. */ - public static @Nullable String getWireTypeString(int wireType) { + public static @Nullable String getWireTypeString(@WireType int wireType) { switch (wireType) { case WIRE_TYPE_VARINT: return "Varint"; diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index f827eda07901..b70072877c66 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -196,11 +196,10 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll if (mCancelled || mFinished) { return; } + mShownOnFinish = shown; setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */); mFinished = true; mListener.onFinished(this); - - mShownOnFinish = shown; } @Override @@ -301,7 +300,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll .withAlpha(side == ISIDE_FLOATING ? 1 : alpha) .withMatrix(mTmpMatrix) .withVisibility(side == ISIDE_FLOATING - ? state.getSource(source.getType()).isVisible() + ? mShownOnFinish : inset != 0 /* visible */) .build(); surfaceParams.add(params); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 708a09467247..fcab9d11f3d6 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -9581,18 +9581,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // First check if context has client, so it saves a service lookup when it doesn't if (mContext.getContentCaptureOptions() == null) return; - // Then check if it's enabled in the context... - final ContentCaptureManager ccm = ai != null ? ai.getContentCaptureManager(mContext) - : mContext.getSystemService(ContentCaptureManager.class); - if (ccm == null || !ccm.isContentCaptureEnabled()) return; - - // ... and finally at the view level - // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled() - if (!isImportantForContentCapture()) return; - - ContentCaptureSession session = getContentCaptureSession(); - if (session == null) return; - if (appeared) { if (!isLaidOut() || getVisibility() != VISIBLE || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) { @@ -9601,21 +9589,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, + isLaidOut() + ", visibleToUser=" + isVisibleToUser() + ", visible=" + (getVisibility() == VISIBLE) + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4 - & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) + & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 - & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); + & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); } return; } - setNotifiedContentCaptureAppeared(); - - if (ai != null) { - ai.delayNotifyContentCaptureEvent(session, this, appeared); - } else { - if (DEBUG_CONTENT_CAPTURE) { - Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); - } - } } else { if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0 || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) { @@ -9624,12 +9603,32 @@ public class View implements Drawable.Callback, KeyEvent.Callback, + isLaidOut() + ", visibleToUser=" + isVisibleToUser() + ", visible=" + (getVisibility() == VISIBLE) + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4 - & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) + & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 - & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); + & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); } return; } + } + + ContentCaptureSession session = getContentCaptureSession(); + if (session == null) return; + + // ... and finally at the view level + // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled() + if (!isImportantForContentCapture()) return; + + if (appeared) { + setNotifiedContentCaptureAppeared(); + + if (ai != null) { + ai.delayNotifyContentCaptureEvent(session, this, appeared); + } else { + if (DEBUG_CONTENT_CAPTURE) { + Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); + } + } + } else { mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java index 4e7ae8a235e7..bedf55d52391 100644 --- a/core/java/com/android/internal/widget/ConversationLayout.java +++ b/core/java/com/android/internal/widget/ConversationLayout.java @@ -93,7 +93,6 @@ public class ConversationLayout extends FrameLayout private MessagingLinearLayout mMessagingLinearLayout; private boolean mShowHistoricMessages; private ArrayList<MessagingGroup> mGroups = new ArrayList<>(); - private TextView mTitleView; private int mLayoutColor; private int mSenderTextColor; private int mMessageTextColor; @@ -108,8 +107,14 @@ public class ConversationLayout extends FrameLayout private boolean mIsCollapsed; private ImageResolver mImageResolver; private ImageView mConversationIcon; + private View mConversationIconContainer; + private int mConversationIconTopPadding; + private int mConversationIconTopPaddingExpandedGroup; + private int mConversationIconTopPaddingNoAppName; + private int mExpandedGroupMessagePaddingNoAppName; private TextView mConversationText; private View mConversationIconBadge; + private ImageView mConversationIconBadgeBg; private Icon mLargeIcon; private View mExpandButtonContainer; private ViewGroup mExpandButtonAndContentContainer; @@ -117,11 +122,12 @@ public class ConversationLayout extends FrameLayout private MessagingLinearLayout mImageMessageContainer; private int mExpandButtonExpandedTopMargin; private int mBadgedSideMargins; - private int mIconSizeBadged; - private int mIconSizeCentered; + private int mConversationAvatarSize; + private int mConversationAvatarSizeExpanded; private CachingIconView mIcon; private View mImportanceRingView; - private int mExpandedGroupTopMargin; + private int mExpandedGroupSideMargin; + private int mExpandedGroupSideMarginFacePile; private View mConversationFacePile; private int mNotificationBackgroundColor; private CharSequence mFallbackChatName; @@ -133,7 +139,12 @@ public class ConversationLayout extends FrameLayout private boolean mExpandable = true; private int mContentMarginEnd; private Rect mMessagingClipRect; - private TextView mAppName; + private ObservableTextView mAppName; + private boolean mAppNameGone; + private int mFacePileAvatarSize; + private int mFacePileAvatarSizeExpandedGroup; + private int mFacePileProtectionWidth; + private int mFacePileProtectionWidthExpanded; public ConversationLayout(@NonNull Context context) { super(context); @@ -165,14 +176,15 @@ public class ConversationLayout extends FrameLayout int size = Math.max(displayMetrics.widthPixels, displayMetrics.heightPixels); mMessagingClipRect = new Rect(0, 0, size, size); setMessagingClippingDisabled(false); - mTitleView = findViewById(R.id.title); mAvatarSize = getResources().getDimensionPixelSize(R.dimen.messaging_avatar_size); mTextPaint.setTextAlign(Paint.Align.CENTER); mTextPaint.setAntiAlias(true); mConversationIcon = findViewById(R.id.conversation_icon); + mConversationIconContainer = findViewById(R.id.conversation_icon_container); mIcon = findViewById(R.id.icon); mImportanceRingView = findViewById(R.id.conversation_icon_badge_ring); mConversationIconBadge = findViewById(R.id.conversation_icon_badge); + mConversationIconBadgeBg = findViewById(R.id.conversation_icon_badge_bg); mIcon.setOnVisibilityChangedListener((visibility) -> { // Always keep the badge visibility in sync with the icon. This is necessary in cases // Where the icon is being hidden externally like in group children. @@ -192,18 +204,40 @@ public class ConversationLayout extends FrameLayout R.dimen.notification_content_margin_end); mBadgedSideMargins = getResources().getDimensionPixelSize( R.dimen.conversation_badge_side_margin); - mIconSizeBadged = getResources().getDimensionPixelSize( - R.dimen.conversation_icon_size_badged); - mIconSizeCentered = getResources().getDimensionPixelSize( - R.dimen.conversation_icon_size_centered); - mExpandedGroupTopMargin = getResources().getDimensionPixelSize( - R.dimen.conversation_icon_margin_top_centered); + mConversationAvatarSize = getResources().getDimensionPixelSize( + R.dimen.conversation_avatar_size); + mConversationAvatarSizeExpanded = getResources().getDimensionPixelSize( + R.dimen.conversation_avatar_size_group_expanded); + mConversationIconTopPadding = getResources().getDimensionPixelSize( + R.dimen.conversation_icon_container_top_padding); + mConversationIconTopPaddingExpandedGroup = getResources().getDimensionPixelSize( + R.dimen.conversation_icon_container_top_padding_small_avatar); + mConversationIconTopPaddingNoAppName = getResources().getDimensionPixelSize( + R.dimen.conversation_icon_container_top_padding_no_app_name); + mExpandedGroupMessagePaddingNoAppName = getResources().getDimensionPixelSize( + R.dimen.expanded_group_conversation_message_padding_without_app_name); + mExpandedGroupSideMargin = getResources().getDimensionPixelSize( + R.dimen.conversation_badge_side_margin_group_expanded); + mExpandedGroupSideMarginFacePile = getResources().getDimensionPixelSize( + R.dimen.conversation_badge_side_margin_group_expanded_face_pile); mConversationFacePile = findViewById(R.id.conversation_face_pile); + mFacePileAvatarSize = getResources().getDimensionPixelSize( + R.dimen.conversation_face_pile_avatar_size); + mFacePileAvatarSizeExpandedGroup = getResources().getDimensionPixelSize( + R.dimen.conversation_face_pile_avatar_size_group_expanded); + mFacePileProtectionWidth = getResources().getDimensionPixelSize( + R.dimen.conversation_face_pile_protection_width); + mFacePileProtectionWidthExpanded = getResources().getDimensionPixelSize( + R.dimen.conversation_face_pile_protection_width_expanded); mFallbackChatName = getResources().getString( R.string.conversation_title_fallback_one_to_one); mFallbackGroupChatName = getResources().getString( R.string.conversation_title_fallback_group_chat); mAppName = findViewById(R.id.app_name_text); + mAppNameGone = mAppName.getVisibility() == GONE; + mAppName.setOnVisibilityChangedListener((visibility) -> { + onAppNameVisibilityChanged(); + }); } @RemotableViewMethod @@ -234,7 +268,7 @@ public class ConversationLayout extends FrameLayout mIsCollapsed = isCollapsed; mMessagingLinearLayout.setMaxDisplayedLines(isCollapsed ? 1 : Integer.MAX_VALUE); updateExpandButton(); - updateContentPaddings(); + updateContentEndPaddings(); } @RemotableViewMethod @@ -354,21 +388,17 @@ public class ConversationLayout extends FrameLayout } } } else { - if (mIsCollapsed) { - if (mLargeIcon != null) { - mConversationIcon.setVisibility(VISIBLE); - mConversationFacePile.setVisibility(GONE); - mConversationIcon.setImageIcon(mLargeIcon); - } else { - mConversationIcon.setVisibility(GONE); - // This will also inflate it! - mConversationFacePile.setVisibility(VISIBLE); - mConversationFacePile = findViewById(R.id.conversation_face_pile); - bindFacePile(); - } - } else { + if (mLargeIcon != null) { + mConversationIcon.setVisibility(VISIBLE); mConversationFacePile.setVisibility(GONE); + mConversationIcon.setImageIcon(mLargeIcon); + } else { mConversationIcon.setVisibility(GONE); + // This will also inflate it! + mConversationFacePile.setVisibility(VISIBLE); + // rebind the value to the inflated view instead of the stub + mConversationFacePile = findViewById(R.id.conversation_face_pile); + bindFacePile(); } } if (TextUtils.isEmpty(conversationText)) { @@ -384,9 +414,10 @@ public class ConversationLayout extends FrameLayout && TextUtils.equals(conversationText, messageSender); messagingGroup.setCanHideSenderIfFirst(canHide); } + updateAppName(); updateIconPositionAndSize(); updateImageMessages(); - updateAppName(); + updatePaddingsBasedOnContentAvailability(); } private void updateImageMessages() { @@ -425,7 +456,7 @@ public class ConversationLayout extends FrameLayout private void bindFacePile() { // Let's bind the face pile - View bottomBackground = mConversationFacePile.findViewById( + ImageView bottomBackground = mConversationFacePile.findViewById( R.id.conversation_face_pile_bottom_background); applyNotificationBackgroundColor(bottomBackground); ImageView bottomView = mConversationFacePile.findViewById( @@ -463,6 +494,38 @@ public class ConversationLayout extends FrameLayout secondLastIcon = createAvatarSymbol("", "", mLayoutColor); } topView.setImageIcon(secondLastIcon); + + int conversationAvatarSize; + int facepileAvatarSize; + int facePileBackgroundSize; + if (mIsCollapsed) { + conversationAvatarSize = mConversationAvatarSize; + facepileAvatarSize = mFacePileAvatarSize; + facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidth; + } else { + conversationAvatarSize = mConversationAvatarSizeExpanded; + facepileAvatarSize = mFacePileAvatarSizeExpandedGroup; + facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidthExpanded; + } + LayoutParams layoutParams = (LayoutParams) mConversationIcon.getLayoutParams(); + layoutParams.width = conversationAvatarSize; + layoutParams.height = conversationAvatarSize; + mConversationFacePile.setLayoutParams(layoutParams); + + layoutParams = (LayoutParams) bottomView.getLayoutParams(); + layoutParams.width = facepileAvatarSize; + layoutParams.height = facepileAvatarSize; + bottomView.setLayoutParams(layoutParams); + + layoutParams = (LayoutParams) topView.getLayoutParams(); + layoutParams.width = facepileAvatarSize; + layoutParams.height = facepileAvatarSize; + topView.setLayoutParams(layoutParams); + + layoutParams = (LayoutParams) bottomBackground.getLayoutParams(); + layoutParams.width = facePileBackgroundSize; + layoutParams.height = facePileBackgroundSize; + bottomBackground.setLayoutParams(layoutParams); } private void updateAppName() { @@ -477,30 +540,61 @@ public class ConversationLayout extends FrameLayout * update the icon position and sizing */ private void updateIconPositionAndSize() { - int gravity; - int marginStart; - int marginTop; - int iconSize; + int sidemargin; + int conversationAvatarSize; if (mIsOneToOne || mIsCollapsed) { - // Badged format - gravity = Gravity.LEFT; - marginStart = mBadgedSideMargins; - marginTop = mBadgedSideMargins; - iconSize = mIconSizeBadged; + sidemargin = mBadgedSideMargins; + conversationAvatarSize = mConversationAvatarSize; } else { - gravity = Gravity.CENTER_HORIZONTAL; - marginStart = 0; - marginTop = mExpandedGroupTopMargin; - iconSize = mIconSizeCentered; + sidemargin = mConversationFacePile.getVisibility() == VISIBLE + ? mExpandedGroupSideMarginFacePile + : mExpandedGroupSideMargin; + conversationAvatarSize = mConversationAvatarSizeExpanded; } LayoutParams layoutParams = (LayoutParams) mConversationIconBadge.getLayoutParams(); - layoutParams.gravity = gravity; - layoutParams.topMargin = marginTop; - layoutParams.setMarginStart(marginStart); - layoutParams.width = iconSize; - layoutParams.height = iconSize; + layoutParams.topMargin = sidemargin; + layoutParams.setMarginStart(sidemargin); mConversationIconBadge.setLayoutParams(layoutParams); + + if (mConversationIcon.getVisibility() == VISIBLE) { + layoutParams = (LayoutParams) mConversationIcon.getLayoutParams(); + layoutParams.width = conversationAvatarSize; + layoutParams.height = conversationAvatarSize; + mConversationIcon.setLayoutParams(layoutParams); + } + } + + private void updatePaddingsBasedOnContentAvailability() { + int containerTopPadding; + int messagingPadding = 0; + if (mIsOneToOne || mIsCollapsed) { + containerTopPadding = mConversationIconTopPadding; + } else { + if (mAppName.getVisibility() != GONE) { + // The app name is visible, let's center outselves in the two lines + containerTopPadding = mConversationIconTopPaddingExpandedGroup; + } else { + // App name is gone, let's center ourselves int he one remaining line + containerTopPadding = mConversationIconTopPaddingNoAppName; + + // The app name is gone and we're a group, we'll need to add some extra padding + // to the messages, since otherwise it will overlap with the group + messagingPadding = mExpandedGroupMessagePaddingNoAppName; + } + } + + mConversationIconContainer.setPaddingRelative( + mConversationIconContainer.getPaddingStart(), + containerTopPadding, + mConversationIconContainer.getPaddingEnd(), + mConversationIconContainer.getPaddingBottom()); + + mMessagingLinearLayout.setPaddingRelative( + mMessagingLinearLayout.getPaddingStart(), + messagingPadding, + mMessagingLinearLayout.getPaddingEnd(), + mMessagingLinearLayout.getPaddingBottom()); } @RemotableViewMethod @@ -678,11 +772,11 @@ public class ConversationLayout extends FrameLayout @RemotableViewMethod public void setNotificationBackgroundColor(int color) { mNotificationBackgroundColor = color; - applyNotificationBackgroundColor(mConversationIconBadge); + applyNotificationBackgroundColor(mConversationIconBadgeBg); } - private void applyNotificationBackgroundColor(View view) { - view.setBackgroundTintList(ColorStateList.valueOf(mNotificationBackgroundColor)); + private void applyNotificationBackgroundColor(ImageView view) { + view.setImageTintList(ColorStateList.valueOf(mNotificationBackgroundColor)); } @RemotableViewMethod @@ -922,7 +1016,7 @@ public class ConversationLayout extends FrameLayout mExpandButtonContainer.setContentDescription(mContext.getText(contentDescriptionId)); } - private void updateContentPaddings() { + private void updateContentEndPaddings() { // Let's make sure the conversation header can't run into the expand button when we're // collapsed and update the paddings of the content @@ -951,6 +1045,14 @@ public class ConversationLayout extends FrameLayout mContentContainer.getPaddingBottom()); } + private void onAppNameVisibilityChanged() { + boolean appNameGone = mAppName.getVisibility() == GONE; + if (appNameGone != mAppNameGone) { + mAppNameGone = appNameGone; + updatePaddingsBasedOnContentAvailability(); + } + } + public void updateExpandability(boolean expandable, @Nullable OnClickListener onClickListener) { mExpandable = expandable; if (expandable) { @@ -960,7 +1062,7 @@ public class ConversationLayout extends FrameLayout // TODO: handle content paddings to end of layout mExpandButtonContainer.setVisibility(GONE); } - updateContentPaddings(); + updateContentEndPaddings(); } @Override diff --git a/core/java/com/android/internal/widget/ObservableTextView.java b/core/java/com/android/internal/widget/ObservableTextView.java new file mode 100644 index 000000000000..1f3c296f0b60 --- /dev/null +++ b/core/java/com/android/internal/widget/ObservableTextView.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.internal.widget; + +import android.annotation.Nullable; +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.RemoteViews; +import android.widget.TextView; + +import java.util.function.Consumer; + +/** + * A text view whose visibility can be observed. + */ +@RemoteViews.RemoteView +public class ObservableTextView extends TextView { + + private Consumer<Integer> mOnVisibilityChangedListener; + + public ObservableTextView(Context context) { + super(context); + } + + public ObservableTextView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public ObservableTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public ObservableTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + if (changedView == this) { + if (mOnVisibilityChangedListener != null) { + mOnVisibilityChangedListener.accept(visibility); + } + } + } + + public void setOnVisibilityChangedListener(Consumer<Integer> listener) { + mOnVisibilityChangedListener = listener; + } +} diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index fc6e639f0aa0..ed2c5b2b4930 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -2653,4 +2653,16 @@ enum PageId { // CATEGORY: SETTINGS // OS: R ADB_WIRELESS_DEVICE_DETAILS = 1836; + + // Open: Settings > Sound > Do Not Disturb > People > Conversations + // OS: R + DND_CONVERSATIONS = 1837; + + // Open: Settings > Sound > Do Not Disturb > People > Calls + // OS: R + DND_CALLS = 1838; + + // Open: Settings > Sound > Do Not Disturb > People > Messages + // OS: R + DND_MESSAGES = 1839; } diff --git a/core/res/res/layout/conversation_face_pile_layout.xml b/core/res/res/layout/conversation_face_pile_layout.xml index 1db38702f926..528562534aab 100644 --- a/core/res/res/layout/conversation_face_pile_layout.xml +++ b/core/res/res/layout/conversation_face_pile_layout.xml @@ -23,21 +23,25 @@ > <ImageView android:id="@+id/conversation_face_pile_top" - android:layout_width="36dp" - android:layout_height="36dp" + android:layout_width="@dimen/messaging_avatar_size" + android:layout_height="@dimen/messaging_avatar_size" android:scaleType="centerCrop" android:layout_gravity="end|top" /> <FrameLayout - android:id="@+id/conversation_face_pile_bottom_background" - android:layout_width="40dp" - android:layout_height="40dp" - android:layout_gravity="start|bottom" - android:background="@drawable/conversation_badge_background"> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="start|bottom"> + <ImageView + android:id="@+id/conversation_face_pile_bottom_background" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/conversation_badge_background" + /> <ImageView android:id="@+id/conversation_face_pile_bottom" - android:layout_width="36dp" - android:layout_height="36dp" + android:layout_width="@dimen/messaging_avatar_size" + android:layout_height="@dimen/messaging_avatar_size" android:scaleType="centerCrop" android:layout_gravity="center" /> diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml index 7bf13ec4ad65..7cadecbbdb91 100644 --- a/core/res/res/layout/notification_template_material_conversation.xml +++ b/core/res/res/layout/notification_template_material_conversation.xml @@ -25,6 +25,7 @@ > <FrameLayout + android:id="@+id/conversation_icon_container" android:layout_width="@dimen/conversation_content_start" android:layout_height="wrap_content" android:gravity="start|top" @@ -175,7 +176,7 @@ </LinearLayout> <!-- App Name --> - <TextView + <com.android.internal.widget.ObservableTextView android:id="@+id/app_name_text" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index f2e25998e0ae..7edb86b2db18 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -694,10 +694,31 @@ <dimen name="conversation_badge_side_margin">36dp</dimen> <!-- size of the notification badge when applied to the conversation icon --> <dimen name="conversation_icon_size_badged">20dp</dimen> - <!-- size of the notification badge when centered in a conversation --> - <dimen name="conversation_icon_size_centered">26dp</dimen> - <!-- margin on the top when the icon is centered for group conversations --> - <dimen name="conversation_icon_margin_top_centered">12dp</dimen> + <!-- size of the conversation avatar in an expanded group --> + <dimen name="conversation_avatar_size_group_expanded">@dimen/messaging_avatar_size</dimen> + <!-- size of the face pile icons --> + <dimen name="conversation_face_pile_avatar_size">@dimen/messaging_avatar_size</dimen> + <!-- size of the face pile icons when the group is expanded --> + <dimen name="conversation_face_pile_avatar_size_group_expanded">25dp</dimen> + <!-- Side margins of the conversation badge in relation to the conversation icon when the group is expanded--> + <dimen name="conversation_badge_side_margin_group_expanded">22dp</dimen> + <!-- Side margins of the conversation badge in relation to the conversation icon when the group is expanded--> + <dimen name="conversation_badge_side_margin_group_expanded_face_pile">18dp</dimen> + <!-- The width of the protection of the face pile layout--> + <dimen name="conversation_face_pile_protection_width">2dp</dimen> + <!-- The width of the protection of the face pile layout when expanded--> + <dimen name="conversation_face_pile_protection_width_expanded">1dp</dimen> + <!-- The padding of the expanded message container when the app name is gone--> + <dimen name="expanded_group_conversation_message_padding_without_app_name">14dp</dimen> + + <!-- The top padding of the conversation icon container in the regular state--> + <dimen name="conversation_icon_container_top_padding">12dp</dimen> + + <!-- The top padding of the conversation icon container when there's no app name present in a group--> + <dimen name="conversation_icon_container_top_padding_no_app_name">9dp</dimen> + + <!-- The top padding of the conversation icon container when the avatar is small--> + <dimen name="conversation_icon_container_top_padding_small_avatar">17.5dp</dimen> <!-- The padding of the conversation header when expanded. This is calculated from the expand button size + notification_content_margin_end --> <dimen name="conversation_header_expanded_padding_end">38dp</dimen> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 163501a5985e..0adef7513bb5 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3874,15 +3874,25 @@ <java-symbol type="id" name="conversation_text" /> <java-symbol type="id" name="message_icon_container" /> <java-symbol type="id" name="conversation_image_message_container" /> + <java-symbol type="id" name="conversation_icon_container" /> <java-symbol type="dimen" name="conversation_expand_button_top_margin_expanded" /> <java-symbol type="dimen" name="messaging_group_singleline_sender_padding_end" /> <java-symbol type="dimen" name="conversation_badge_side_margin" /> - <java-symbol type="dimen" name="conversation_icon_size_badged" /> - <java-symbol type="dimen" name="conversation_icon_size_centered" /> - <java-symbol type="dimen" name="conversation_icon_margin_top_centered" /> + <java-symbol type="dimen" name="conversation_avatar_size" /> + <java-symbol type="dimen" name="conversation_avatar_size_group_expanded" /> + <java-symbol type="dimen" name="conversation_face_pile_avatar_size" /> + <java-symbol type="dimen" name="conversation_face_pile_avatar_size_group_expanded" /> + <java-symbol type="dimen" name="conversation_face_pile_protection_width" /> + <java-symbol type="dimen" name="conversation_face_pile_protection_width_expanded" /> + <java-symbol type="dimen" name="conversation_badge_side_margin_group_expanded" /> + <java-symbol type="dimen" name="conversation_badge_side_margin_group_expanded_face_pile" /> <java-symbol type="dimen" name="conversation_content_start" /> + <java-symbol type="dimen" name="expanded_group_conversation_message_padding_without_app_name" /> <java-symbol type="dimen" name="messaging_layout_margin_end" /> <java-symbol type="dimen" name="conversation_header_expanded_padding_end" /> + <java-symbol type="dimen" name="conversation_icon_container_top_padding" /> + <java-symbol type="dimen" name="conversation_icon_container_top_padding_small_avatar" /> + <java-symbol type="dimen" name="conversation_icon_container_top_padding_no_app_name" /> <java-symbol type="layout" name="notification_template_material_conversation" /> <java-symbol type="layout" name="conversation_face_pile_layout" /> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index d8bd81e80ed5..1efde8681352 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -255,6 +255,7 @@ applications that come with the platform </privapp-permissions> <privapp-permissions package="com.android.networkstack.tethering"> + <permission name="android.permission.BLUETOOTH_PRIVILEGED" /> <permission name="android.permission.MANAGE_USB"/> <permission name="android.permission.MODIFY_PHONE_STATE"/> <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/> @@ -398,6 +399,10 @@ applications that come with the platform <permission name="android.permission.REGISTER_STATS_PULL_ATOM"/> <!-- Permission required for testing system audio effect APIs. --> <permission name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"/> + <!-- Permissions required for CTS test - TunerTest --> + <permission name="android.permission.ACCESS_TV_DESCRAMBLER" /> + <permission name="android.permission.ACCESS_TV_TUNER" /> + <permission name="android.permission.TUNER_RESOURCE_ACCESS" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java index b943fe589270..d654b45da092 100644 --- a/media/java/android/media/tv/tuner/filter/Filter.java +++ b/media/java/android/media/tv/tuner/filter/Filter.java @@ -22,7 +22,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.hardware.tv.tuner.V1_0.Constants; +import android.media.tv.tuner.Tuner; import android.media.tv.tuner.Tuner.Result; +import android.media.tv.tuner.TunerUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -178,13 +180,14 @@ public class Filter implements AutoCloseable { */ public static final int STATUS_OVERFLOW = Constants.DemuxFilterStatus.OVERFLOW; - private long mNativeContext; private FilterCallback mCallback; private Executor mExecutor; private final int mId; private int mMainType; private int mSubtype; + private Filter mSource; + private boolean mStarted; private native int nativeConfigureFilter( int type, int subType, FilterConfiguration settings); @@ -202,6 +205,9 @@ public class Filter implements AutoCloseable { } private void onFilterStatus(int status) { + if (mCallback != null && mExecutor != null) { + mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status)); + } } private void onFilterEvent(FilterEvent[] events) { @@ -266,10 +272,18 @@ public class Filter implements AutoCloseable { * @param source the filter instance which provides data input. Switch to * use demux as data source if the filter instance is NULL. * @return result status of the operation. + * @throws IllegalStateException if the data source has been set. */ @Result public int setDataSource(@Nullable Filter source) { - return nativeSetDataSource(source); + if (mSource != null) { + throw new IllegalStateException("Data source is existing"); + } + int res = nativeSetDataSource(source); + if (res == Tuner.RESULT_SUCCESS) { + mSource = source; + } + return res; } /** @@ -328,6 +342,9 @@ public class Filter implements AutoCloseable { */ @Override public void close() { - nativeClose(); + int res = nativeClose(); + if (res != Tuner.RESULT_SUCCESS) { + TunerUtils.throwExceptionForResult(res, "Failed to close filter."); + } } } diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index 95ce07d3c55e..29dfd730a84c 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -2448,11 +2448,11 @@ static DemuxFilterSettings getFilterConfiguration( return filterSettings; } -static int copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jint offset, int size) { - ALOGD("copyData, size=%d, offset=%d", size, offset); +static jint copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jlong offset, jlong size) { + ALOGD("copyData, size=%ld, offset=%ld", (long) size, (long) offset); - int available = filter->mFilterMQ->availableToRead(); - ALOGD("copyData, available=%d", available); + jlong available = filter->mFilterMQ->availableToRead(); + ALOGD("copyData, available=%ld", (long) available); size = std::min(size, available); jboolean isCopy; @@ -2474,7 +2474,7 @@ static int copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jint offs return size; } -static int android_media_tv_Tuner_configure_filter( +static jint android_media_tv_Tuner_configure_filter( JNIEnv *env, jobject filter, int type, int subtype, jobject settings) { ALOGD("configure filter type=%d, subtype=%d", type, subtype); sp<Filter> filterSp = getFilter(env, filter); @@ -2485,9 +2485,14 @@ static int android_media_tv_Tuner_configure_filter( } DemuxFilterSettings filterSettings = getFilterConfiguration(env, type, subtype, settings); Result res = iFilterSp->configure(filterSettings); + + if (res != Result::SUCCESS) { + return (jint) res; + } + MQDescriptorSync<uint8_t> filterMQDesc; - if (res == Result::SUCCESS && filterSp->mFilterMQ == NULL) { - Result getQueueDescResult = Result::UNKNOWN_ERROR; + Result getQueueDescResult = Result::UNKNOWN_ERROR; + if (filterSp->mFilterMQ == NULL) { iFilterSp->getQueueDesc( [&](Result r, const MQDescriptorSync<uint8_t>& desc) { filterMQDesc = desc; @@ -2500,59 +2505,97 @@ static int android_media_tv_Tuner_configure_filter( filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag)); } } - return (int)res; + return (jint) getQueueDescResult; } -static int android_media_tv_Tuner_get_filter_id(JNIEnv*, jobject) { - return 0; +static jint android_media_tv_Tuner_get_filter_id(JNIEnv* env, jobject filter) { + sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); + if (iFilterSp == NULL) { + ALOGD("Failed to get filter ID: filter not found"); + return (int) Result::INVALID_STATE; + } + Result res; + uint32_t id; + iFilterSp->getId( + [&](Result r, uint32_t filterId) { + res = r; + id = filterId; + }); + if (res != Result::SUCCESS) { + return (jint) Constant::INVALID_FILTER_ID; + } + return (jint) id; } -static int android_media_tv_Tuner_set_filter_data_source(JNIEnv*, jobject, jobject) { - return 0; +static jint android_media_tv_Tuner_set_filter_data_source( + JNIEnv* env, jobject filter, jobject srcFilter) { + sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); + if (iFilterSp == NULL) { + ALOGD("Failed to set filter data source: filter not found"); + return (jint) Result::INVALID_STATE; + } + Result r; + if (srcFilter == NULL) { + r = iFilterSp->setDataSource(NULL); + } else { + sp<IFilter> srcSp = getFilter(env, srcFilter)->getIFilter(); + if (iFilterSp == NULL) { + ALOGD("Failed to set filter data source: src filter not found"); + return (jint) Result::INVALID_STATE; + } + r = iFilterSp->setDataSource(srcSp); + } + return (jint) r; } -static int android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) { - sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); - if (filterSp == NULL) { +static jint android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) { + sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); + if (iFilterSp == NULL) { ALOGD("Failed to start filter: filter not found"); - return false; + return (jint) Result::INVALID_STATE; } - Result r = filterSp->start(); - return (int) r; + Result r = iFilterSp->start(); + return (jint) r; } -static int android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) { - sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); - if (filterSp == NULL) { +static jint android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) { + sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); + if (iFilterSp == NULL) { ALOGD("Failed to stop filter: filter not found"); - return false; + return (jint) Result::INVALID_STATE; } - Result r = filterSp->stop(); - return (int) r; + Result r = iFilterSp->stop(); + return (jint) r; } -static int android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) { - sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); - if (filterSp == NULL) { +static jint android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) { + sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); + if (iFilterSp == NULL) { ALOGD("Failed to flush filter: filter not found"); - return false; + return (jint) Result::INVALID_STATE; } - Result r = filterSp->flush(); - return (int) r; + Result r = iFilterSp->flush(); + return (jint) r; } -static int android_media_tv_Tuner_read_filter_fmq( +static jint android_media_tv_Tuner_read_filter_fmq( JNIEnv *env, jobject filter, jbyteArray buffer, jlong offset, jlong size) { sp<Filter> filterSp = getFilter(env, filter); if (filterSp == NULL) { ALOGD("Failed to read filter FMQ: filter not found"); - return 0; + return (jint) Result::INVALID_STATE; } return copyData(env, filterSp, buffer, offset, size); } -static int android_media_tv_Tuner_close_filter(JNIEnv*, jobject) { - return 0; +static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) { + sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); + if (iFilterSp == NULL) { + ALOGD("Failed to close filter: filter not found"); + return (jint) Result::INVALID_STATE; + } + Result r = iFilterSp->close(); + return (jint) r; } static sp<TimeFilter> getTimeFilter(JNIEnv *env, jobject filter) { @@ -2660,8 +2703,8 @@ static int android_media_tv_Tuner_add_pid( if (descramblerSp == NULL) { return false; } - sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); - Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), filterSp); + sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); + Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), iFilterSp); return (int)result; } @@ -2671,8 +2714,8 @@ static int android_media_tv_Tuner_remove_pid( if (descramblerSp == NULL) { return false; } - sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); - Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), filterSp); + sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); + Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), iFilterSp); return (int)result; } @@ -2702,21 +2745,21 @@ static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv*, jobject) { static int android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr(); - sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); - if (dvrSp == NULL || filterSp == NULL) { + sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); + if (dvrSp == NULL || iFilterSp == NULL) { return false; } - Result result = dvrSp->attachFilter(filterSp); + Result result = dvrSp->attachFilter(iFilterSp); return (int) result; } static int android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr(); - sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); - if (dvrSp == NULL || filterSp == NULL) { + sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); + if (dvrSp == NULL || iFilterSp == NULL) { return false; } - Result result = dvrSp->detachFilter(filterSp); + Result result = dvrSp->detachFilter(iFilterSp); return (int) result; } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index 9ae9b4a46227..b1300a97a324 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -440,8 +440,9 @@ public class LocalMediaManager implements BluetoothCallback { MediaDevice connectDevice = getMediaDeviceById(mMediaDevices, id); connectDevice = connectDevice != null ? connectDevice : updateCurrentConnectedDevice(); - connectDevice.setState(MediaDeviceState.STATE_CONNECTED); - + if (connectDevice != null) { + connectDevice.setState(MediaDeviceState.STATE_CONNECTED); + } if (connectDevice == mCurrentConnectedDevice) { Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected!"); return; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java index 559187d2c38c..6b3a97f8c8de 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java @@ -450,6 +450,12 @@ public class LocalMediaManagerTest { } @Test + public void onConnectedDeviceChanged_nullConnectedDevice_noException() { + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_2); + } + + @Test public void onDeviceAttributesChanged_shouldDispatchDeviceListUpdate() { mLocalMediaManager.registerCallback(mCallback); diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 24cc3c901920..a36949b9e1ff 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -540,6 +540,7 @@ public class SettingsBackupTest { Settings.Global.WIFI_FREQUENCY_BAND, Settings.Global.WIFI_IDLE_MS, Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, + Settings.Global.WIFI_MIGRATION_COMPLETED, Settings.Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS, Settings.Global.WIFI_NETWORK_SHOW_RSSI, Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 0230970cfa83..c7fb00a8130c 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -284,6 +284,11 @@ <!-- Permission required for testing system audio effect APIs. --> <uses-permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"/> + <!-- Permissions required for CTS test - TunerTest --> + <uses-permission android:name="android.permission.ACCESS_TV_DESCRAMBLER" /> + <uses-permission android:name="android.permission.ACCESS_TV_TUNER" /> + <uses-permission android:name="android.permission.TUNER_RESOURCE_ACCESS" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index b906442b6ba0..bb0fa2d2c7cb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -340,7 +340,7 @@ public class KeyguardIndicationController implements StateListener, mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked); mTextView.setTextColor(mInitialTextColorState); } else if (!TextUtils.isEmpty(mTransientIndication)) { - if (powerIndication != null) { + if (powerIndication != null && !mTransientIndication.equals(powerIndication)) { String indication = mContext.getResources().getString( R.string.keyguard_indication_trust_unlocked_plugged_in, mTransientIndication, powerIndication); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java index 4882a235c5d8..82f7c71c48cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java @@ -117,11 +117,6 @@ public class ImageTransformState extends TransformState { } @Override - protected boolean transformScale(TransformState otherState) { - return sameAs(otherState); - } - - @Override public void recycle() { super.recycle(); if (getClass() == ImageTransformState.class) { 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 82fb49144181..27109d2acfa2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java @@ -248,7 +248,7 @@ public class TransformState { } protected boolean transformScale(TransformState otherState) { - return false; + return sameAs(otherState); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt index 91a2e7c815d4..593de23c58de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt @@ -53,6 +53,9 @@ class NotificationConversationTemplateViewWrapper constructor( private lateinit var conversationTitle: View private lateinit var importanceRing: View private lateinit var appName: View + private var facePileBottomBg: View? = null + private var facePileBottom: View? = null + private var facePileTop: View? = null private fun resolveViews() { messagingLinearLayout = conversationLayout.messagingLinearLayout @@ -67,6 +70,10 @@ class NotificationConversationTemplateViewWrapper constructor( importanceRing = requireViewById(com.android.internal.R.id.conversation_icon_badge_ring) appName = requireViewById(com.android.internal.R.id.app_name_text) conversationTitle = requireViewById(com.android.internal.R.id.conversation_text) + facePileTop = findViewById(com.android.internal.R.id.conversation_face_pile_top) + facePileBottom = findViewById(com.android.internal.R.id.conversation_face_pile_bottom) + facePileBottomBg = + findViewById(com.android.internal.R.id.conversation_face_pile_bottom_background) } } @@ -118,7 +125,10 @@ class NotificationConversationTemplateViewWrapper constructor( conversationIcon, conversationBadgeBg, expandButton, - importanceRing + importanceRing, + facePileTop, + facePileBottom, + facePileBottomBg ) } @@ -140,9 +150,9 @@ class NotificationConversationTemplateViewWrapper constructor( else super.getMinLayoutHeight() - private fun addTransformedViews(vararg vs: View) = - vs.forEach(mTransformationHelper::addTransformedView) + private fun addTransformedViews(vararg vs: View?) = + vs.forEach { view -> view?.let(mTransformationHelper::addTransformedView) } - private fun addViewsTransformingToSimilar(vararg vs: View) = - vs.forEach(mTransformationHelper::addViewTransformingToSimilar) + private fun addViewsTransformingToSimilar(vararg vs: View?) = + vs.forEach { view -> view?.let(mTransformationHelper::addViewTransformingToSimilar) } } diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml index c71d0d7bc543..9328611f5d3f 100644 --- a/packages/Tethering/AndroidManifest.xml +++ b/packages/Tethering/AndroidManifest.xml @@ -27,7 +27,7 @@ added to the privileged permissions whitelist for that package. --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.BLUETOOTH" /> - <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> + <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" /> <uses-permission android:name="android.permission.BROADCAST_STICKY" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.MANAGE_USB" /> diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index 61c6ef5cfda9..bc38fbf50000 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -274,23 +274,38 @@ public class TouchExplorer extends BaseEventStreamTransformation public void onAccessibilityEvent(AccessibilityEvent event) { final int eventType = event.getEventType(); + if (eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) { + sendsPendingA11yEventsIfNeed(); + } + super.onAccessibilityEvent(event); + } + + /* + * Sends pending {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END} or {@{@link + * AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END}} after receiving last hover exit + * event. + */ + private void sendsPendingA11yEventsIfNeed() { + // The last hover exit A11y event should be sent by view after receiving hover exit motion + // event. In some view hierarchy, the ViewGroup transforms hover move motion event to hover + // exit motion event and than dispatch to itself. It causes unexpected A11y exit events. + if (mSendHoverExitDelayed.isPending()) { + return; + } // The event for gesture end should be strictly after the // last hover exit event. - if (mSendTouchExplorationEndDelayed.isPending() - && eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) { - mSendTouchExplorationEndDelayed.cancel(); + if (mSendTouchExplorationEndDelayed.isPending()) { + mSendTouchExplorationEndDelayed.cancel(); mDispatcher.sendAccessibilityEvent( AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END); } // The event for touch interaction end should be strictly after the // last hover exit and the touch exploration gesture end events. - if (mSendTouchInteractionEndDelayed.isPending() - && eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) { + if (mSendTouchInteractionEndDelayed.isPending()) { mSendTouchInteractionEndDelayed.cancel(); mDispatcher.sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); } - super.onAccessibilityEvent(event); } @Override diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index f3d42ad1c793..1f0146ad815d 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -693,7 +693,7 @@ public class AudioService extends IAudioService.Stub AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = defaultCallVolume; } else { AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = - (maxCallVolume * 3) / 4; + (MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] * 3) / 4; } int maxMusicVolume = SystemProperties.getInt("ro.config.media_vol_steps", -1); diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java index 28c5a2857aa6..6dded00321b5 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -657,12 +657,12 @@ public class TunerResourceManagerService extends SystemService { } private void enforceTunerAccessPermission(String apiName) { - getContext().enforceCallingPermission("android.Manifest.permission.ACCESS_TV_TUNER", + getContext().enforceCallingPermission("android.permission.ACCESS_TV_TUNER", TAG + ": " + apiName); } private void enforceDescramblerAccessPermission(String apiName) { - getContext().enforceCallingPermission("android.Manifest.permission.ACCESS_TV_DESCRAMBLER", + getContext().enforceCallingPermission("android.permission.ACCESS_TV_DESCRAMBLER", TAG + ": " + apiName); } } diff --git a/wifi/java/android/net/wifi/WifiMigration.java b/wifi/java/android/net/wifi/WifiMigration.java index 87afdc59c2b9..5792d27a94f9 100755 --- a/wifi/java/android/net/wifi/WifiMigration.java +++ b/wifi/java/android/net/wifi/WifiMigration.java @@ -522,7 +522,12 @@ public final class WifiMigration { */ @NonNull public static SettingsMigrationData loadFromSettings(@NonNull Context context) { - return new SettingsMigrationData.Builder() + if (Settings.Global.getInt( + context.getContentResolver(), Settings.Global.WIFI_MIGRATION_COMPLETED, 0) == 1) { + // migration already complete, ignore. + return null; + } + SettingsMigrationData data = new SettingsMigrationData.Builder() .setScanAlwaysAvailable( Settings.Global.getInt(context.getContentResolver(), Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1) @@ -545,5 +550,9 @@ public final class WifiMigration { Settings.Global.getInt(context.getContentResolver(), Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0) == 1) .build(); + Settings.Global.putInt( + context.getContentResolver(), Settings.Global.WIFI_MIGRATION_COMPLETED, 1); + return data; + } } |