Merge "Theme fixit for Car Sys UI"

This commit is contained in:
Arnaud Berry
2019-03-21 18:50:11 +00:00
committed by Android (Google) Code Review
17 changed files with 422 additions and 131 deletions

View File

@@ -32,7 +32,6 @@ android_app {
"SystemUISharedLib",
"SettingsLib",
"android.car.userlib",
"androidx.car_car",
"androidx.legacy_legacy-support-v4",
"androidx.recyclerview_recyclerview",
"androidx.preference_preference",
@@ -46,7 +45,6 @@ android_app {
"androidx.slice_slice-builders",
"androidx.arch.core_core-runtime",
"androidx.lifecycle_lifecycle-extensions",
"car-theme-lib-bp",
"SystemUI-tags",
"SystemUI-proto",
],

View File

@@ -14,12 +14,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:visibility="gone">
<LinearLayout
android:id="@+id/container"
@@ -27,20 +27,21 @@
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/car_status_bar_header"
android:theme="@android:style/Theme"
android:layout_alignParentTop="true"/>
<include
layout="@layout/car_status_bar_header"
android:layout_alignParentTop="true"
android:theme="@android:style/Theme"/>
<com.android.systemui.statusbar.car.UserGridRecyclerView
android:id="@+id/user_grid"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/car_user_switcher_margin_top"
android:theme="@style/PagedListTheme"
app:verticallyCenterListContent="true"
app:showPagedListViewDivider="false"
app:gutter="both"
app:itemSpacing="@dimen/car_user_switcher_vertical_spacing_between_users"/>
android:layout_height="match_parent">
<com.android.systemui.statusbar.car.UserGridRecyclerView
android:id="@+id/user_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="@dimen/car_user_switcher_margin_top"/>
</FrameLayout>
</LinearLayout>
</FrameLayout>

View File

@@ -28,7 +28,6 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/user_switcher_container"
android:clipChildren="false"
android:layout_width="match_parent"
@@ -37,11 +36,7 @@
<com.android.systemui.statusbar.car.UserGridRecyclerView
android:id="@+id/user_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="@style/PagedListTheme"
app:showPagedListViewDivider="false"
app:gutter="both"
app:itemSpacing="@dimen/car_user_switcher_vertical_spacing_between_users"/>
android:layout_height="match_parent"/>
</RelativeLayout>

View File

@@ -14,15 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
<androidx.car.widget.PagedListView
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/volume_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="@dimen/volume_dialog_panel_width"
android:theme="@style/PagedListViewTheme"
app:gutter="none"
app:scrollBarEnabled="false"
app:listDividerColor="@color/list_divider_color"
app:showPagedListViewDivider="true"/>
android:minWidth="@dimen/volume_dialog_panel_width"/>

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/car_volume_item_height">
<!-- Primary Action. -->
<ImageView
android:id="@+id/primary_icon"
android:layout_width="@dimen/car_primary_icon_size"
android:layout_centerVertical="true"
android:layout_marginStart="@dimen/car_volume_item_margin_horizontal"
android:layout_alignParentStart="true"
android:layout_height="@dimen/car_primary_icon_size"/>
<!-- Note: the horizontal padding and offset are set to 0 so that the track and thumb
aligns with the proper keylines. -->
<SeekBar
android:id="@+id/seek_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/car_volume_item_seekbar_margin_vertical"
android:layout_marginTop="@dimen/car_volume_item_seekbar_margin_vertical"
android:min="0"
android:paddingBottom="@dimen/car_volume_item_seekbar_padding_vertical"
android:layout_centerVertical="true"
android:paddingEnd="0dp"
android:paddingStart="0dp"
android:paddingTop="@dimen/car_volume_item_seekbar_padding_vertical"
android:splitTrack="false"
android:layout_toStartOf="@id/supplemental_icon_divider"
android:layout_marginStart="@dimen/car_volume_item_seekbar_margin_start"
android:layout_marginEnd="@dimen/car_volume_item_seekbar_margin_end"
android:thumbOffset="0dp"/>
<!-- Supplemental action. -->
<View
android:id="@+id/supplemental_icon_divider"
android:layout_width="@dimen/car_volume_item_divider_width"
android:layout_height="@dimen/car_volume_item_divider_height"
android:layout_marginEnd="@dimen/car_volume_item_divider_margin_end"
android:layout_centerVertical="true"
android:layout_toStartOf="@id/supplemental_icon"
android:background="@color/car_volume_item_divider_color"/>
<ImageView
android:id="@+id/supplemental_icon"
android:layout_width="@dimen/car_primary_icon_size"
android:layout_height="@dimen/car_primary_icon_size"
android:background="?android:attr/selectableItemBackground"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_marginEnd="@dimen/car_volume_item_margin_horizontal"
android:scaleType="fitCenter"/>
</RelativeLayout>

View File

@@ -32,19 +32,14 @@
android:translationZ="2dp"
/>
<androidx.car.widget.PagedListView
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/notifications"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
android:theme="@style/PagedListTheme"
app:gutter="none"
app:itemSpacing="@dimen/item_spacing"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:scrollBarEnabled="false"
app:showPagedListViewDivider="false"/>
app:layout_constraintEnd_toEndOf="parent"/>
</com.android.car.notification.CarNotificationView>

View File

@@ -45,4 +45,6 @@
<color name="keyguard_button_text_color">@android:color/black</color>
<color name="list_divider_color">@*android:color/car_list_divider_light</color>
<color name="car_volume_item_divider_color">@*android:color/car_list_divider</color>
<color name="car_volume_item_background_color">@*android:color/car_card_dark</color>
</resources>

View File

@@ -26,7 +26,7 @@
<!-- The amount by which to scale up the status bar icons. -->
<item name="status_bar_icon_scale_factor" format="float" type="dimen">1.75</item>
<dimen name="car_primary_icon_size">36dp</dimen>
<dimen name="car_primary_icon_size">@*android:dimen/car_primary_icon_size</dimen>
<!-- dimensions for the car user switcher -->
<dimen name="car_user_switcher_name_text_size">@dimen/car_body1_size</dimen>
@@ -59,4 +59,33 @@
<dimen name="car_keyline_1">24dp</dimen>
<dimen name="car_keyline_2">96dp</dimen>
<dimen name="car_keyline_3">128dp</dimen>
<dimen name="privacy_chip_icon_max_height">100dp</dimen>
<!-- Height of icons in Ongoing App Ops dialog. Both App Op icon and application icon -->
<dimen name="ongoing_appops_dialog_icon_height">48dp</dimen>
<!-- Margin between text lines in Ongoing App Ops dialog -->
<dimen name="ongoing_appops_dialog_text_margin">15dp</dimen>
<!-- Padding around Ongoing App Ops dialog content -->
<dimen name="ongoing_appops_dialog_content_padding">24dp</dimen>
<!-- Margins around the Ongoing App Ops chip. In landscape, the side margins are 0 -->
<dimen name="ongoing_appops_chip_margin">12dp</dimen>
<!-- Start and End padding for Ongoing App Ops chip -->
<dimen name="ongoing_appops_chip_side_padding">6dp</dimen>
<!-- Padding between background of Ongoing App Ops chip and content -->
<dimen name="ongoing_appops_chip_bg_padding">4dp</dimen>
<!-- Radius of Ongoing App Ops chip corners -->
<dimen name="ongoing_appops_chip_bg_corner_radius">12dp</dimen>
<!-- Car volume dimens. -->
<dimen name="car_volume_item_height">@*android:dimen/car_single_line_list_item_height</dimen>
<dimen name="car_volume_item_margin_horizontal">@*android:dimen/car_keyline_1</dimen>
<dimen name="car_volume_item_seekbar_margin_vertical">@*android:dimen/car_padding_1</dimen>
<dimen name="car_volume_item_seekbar_margin_start">@*android:dimen/car_keyline_3</dimen>
<dimen name="car_volume_item_seekbar_margin_end">@*android:dimen/car_padding_4</dimen>
<dimen name="car_volume_item_seekbar_padding_vertical">@*android:dimen/car_seekbar_padding</dimen>
<dimen name="car_volume_item_divider_height">60dp</dimen>
<dimen name="car_volume_item_divider_width">1dp</dimen>
<dimen name="car_volume_item_divider_margin_end">@*android:dimen/car_padding_4</dimen>
<dimen name="car_volume_item_corner_radius">@*android:dimen/car_radius_3</dimen>
</resources>

View File

@@ -46,11 +46,4 @@
<item name="android:layout_width">96dp</item>
<item name="android:background">@drawable/nav_button_background</item>
</style>
<style name="PagedListViewTheme" parent="@style/Theme.CarSupportWrapper.NoActionBar">
<item name="android:background">@*android:color/car_background</item>
<item name="listItemBackgroundColor">@*android:color/car_background</item>
<item name="dividerEndMargin">@dimen/car_keyline_1</item>
<item name="dividerStartMargin">@dimen/car_keyline_1</item>
</style>
</resources>

View File

@@ -18,10 +18,6 @@
-->
<resources>
<!--This Theme contains attributes required for components from the car support lib -->
<style name="PagedListTheme" parent="Theme.CarSupportWrapper.NoActionBar">
</style>
<style name="Theme.Notification" parent="Theme.DeviceDefault.NoActionBar.Notification">
</style>
</resources>

View File

@@ -16,11 +16,11 @@
package com.android.systemui.notifications;
import android.app.ActivityManager;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.car.Car;
import android.car.CarNotConnectedException;
import android.car.drivingstate.CarUxRestrictionsManager;
@@ -113,7 +113,7 @@ public class NotificationsUI extends SystemUI
ServiceManager.getService(Context.STATUS_BAR_SERVICE)),
launchResult -> {
if (launchResult == ActivityManager.START_TASK_TO_FRONT
|| launchResult == ActivityManager.START_SUCCESS){
|| launchResult == ActivityManager.START_SUCCESS) {
closeCarNotifications(DEFAULT_FLING_VELOCITY);
}
});
@@ -179,8 +179,7 @@ public class NotificationsUI extends SystemUI
}
});
RecyclerView notificationList = mCarNotificationWindow
.findViewById(com.android.car.notification.R.id.recycler_view);
RecyclerView notificationList = mCarNotificationWindow.findViewById(R.id.notifications);
// register a scroll listener so we can figure out if we are at the bottom of the
// list of notifications
notificationList.addOnScrollListener(new RecyclerView.OnScrollListener() {
@@ -202,7 +201,7 @@ public class NotificationsUI extends SystemUI
// There's a view installed at a higher z-order such that we can intercept the ACTION_DOWN
// to set the initial click state.
mCarNotificationWindow.findViewById(R.id.glass_pane).setOnTouchListener((v, event) -> {
if (event.getActionMasked() == MotionEvent.ACTION_UP ) {
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
mNotificationListAtBottomAtTimeOfTouch = false;
}
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
@@ -259,7 +258,7 @@ public class NotificationsUI extends SystemUI
public boolean onTouch(View v, MotionEvent event) {
// reset mNotificationListAtBottomAtTimeOfTouch here since the "glass pane" will not
// get the up event
if (event.getActionMasked() == MotionEvent.ACTION_UP ) {
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
mNotificationListAtBottomAtTimeOfTouch = false;
}
boolean wasScrolledUp = mScrollUpDetector.onTouchEvent(event);
@@ -351,7 +350,7 @@ public class NotificationsUI extends SystemUI
public boolean onFling(MotionEvent event1, MotionEvent event2,
float velocityX, float velocityY) {
if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
|| Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY){
|| Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
// swipe was not vertical or was not fast enough
return false;
}
@@ -435,8 +434,7 @@ public class NotificationsUI extends SystemUI
mNotificationViewController.disable();
mIsShowing = false;
mIsTracking = false;
RecyclerView notificationListView = mCarNotificationWindow.findViewById(
com.android.car.notification.R.id.recycler_view);
RecyclerView notificationListView = mCarNotificationWindow.findViewById(R.id.notifications);
notificationListView.scrollToPosition(0);
}

View File

@@ -79,7 +79,7 @@ public class CarQSFragment extends Fragment implements QS {
mUserGridView = mUserSwitcherContainer.findViewById(R.id.user_grid);
GridLayoutManager layoutManager = new GridLayoutManager(context,
context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
mUserGridView.getRecyclerView().setLayoutManager(layoutManager);
mUserGridView.setLayoutManager(layoutManager);
mUserGridView.buildAdapter();
mUserSwitchCallback = new UserSwitchCallback();

View File

@@ -45,7 +45,7 @@ public class FullscreenUserSwitcher {
mUserGridView = container.findViewById(R.id.user_grid);
GridLayoutManager layoutManager = new GridLayoutManager(context,
context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
mUserGridView.getRecyclerView().setLayoutManager(layoutManager);
mUserGridView.setLayoutManager(layoutManager);
mUserGridView.buildAdapter();
mUserGridView.setUserSelectionListener(this::onUserSelected);

View File

@@ -28,6 +28,7 @@ import android.content.DialogInterface;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -36,9 +37,9 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.car.widget.PagedListView;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.util.UserIcons;
@@ -52,7 +53,7 @@ import java.util.List;
* Displays a GridLayout with icons for the users in the system to allow switching between users.
* One of the uses of this is for the lock screen in auto.
*/
public class UserGridRecyclerView extends PagedListView implements
public class UserGridRecyclerView extends RecyclerView implements
CarUserManagerHelper.OnUsersUpdateListener {
private UserSelectionListener mUserSelectionListener;
private UserAdapter mAdapter;
@@ -63,6 +64,9 @@ public class UserGridRecyclerView extends PagedListView implements
super(context, attrs);
mContext = context;
mCarUserManagerHelper = new CarUserManagerHelper(mContext);
addItemDecoration(new ItemSpacingDecoration(context.getResources().getDimensionPixelSize(
R.dimen.car_user_switcher_vertical_spacing_between_users)));
}
/**
@@ -391,4 +395,31 @@ public class UserGridRecyclerView extends PagedListView implements
void onUserSelected(UserRecord record);
}
/**
* A {@link RecyclerView.ItemDecoration} that will add spacing between each item in the
* RecyclerView that it is added to.
*/
private static class ItemSpacingDecoration extends RecyclerView.ItemDecoration {
private int mItemSpacing;
private ItemSpacingDecoration(int itemSpacing) {
mItemSpacing = itemSpacing;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
int position = parent.getChildAdapterPosition(view);
// Skip offset for last item except for GridLayoutManager.
if (position == state.getItemCount() - 1
&& !(parent.getLayoutManager() instanceof GridLayoutManager)) {
return;
}
outRect.bottom = mItemSpacing;
}
}
}

View File

@@ -32,9 +32,7 @@ import android.content.DialogInterface;
import android.content.ServiceConnection;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.os.Debug;
@@ -46,7 +44,6 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.util.Xml;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
@@ -56,12 +53,8 @@ import android.view.WindowManager;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import androidx.car.widget.ListItem;
import androidx.car.widget.ListItemAdapter;
import androidx.car.widget.ListItemAdapter.BackgroundStyle;
import androidx.car.widget.ListItemProvider.ListProvider;
import androidx.car.widget.PagedListView;
import androidx.car.widget.SeekbarListItem;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.systemui.R;
import com.android.systemui.plugins.VolumeDialog;
@@ -96,13 +89,13 @@ public class CarVolumeDialogImpl implements VolumeDialog {
private final SparseArray<VolumeItem> mVolumeItems = new SparseArray<>();
// Available volume items in car audio manager.
private final List<VolumeItem> mAvailableVolumeItems = new ArrayList<>();
// Volume items in the PagedListView.
private final List<ListItem> mVolumeLineItems = new ArrayList<>();
// Volume items in the RecyclerView.
private final List<CarVolumeItem> mCarVolumeLineItems = new ArrayList<>();
private final KeyguardManager mKeyguard;
private Window mWindow;
private CustomDialog mDialog;
private PagedListView mListView;
private ListItemAdapter mPagedListAdapter;
private RecyclerView mListView;
private CarVolumeItemAdapter mVolumeItemsAdapter;
private Car mCar;
private CarAudioManager mCarAudioManager;
private final CarAudioManager.CarVolumeCallback mVolumeChangeCallback =
@@ -126,7 +119,7 @@ public class CarVolumeDialogImpl implements VolumeDialog {
// callback. Updating the seekbar at the same time could block the continuous
// seeking.
if (value != volumeItem.progress) {
volumeItem.listItem.setProgress(value);
volumeItem.carVolumeItem.setProgress(value);
volumeItem.progress = value;
}
if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
@@ -160,13 +153,13 @@ public class CarVolumeDialogImpl implements VolumeDialog {
// The first one is the default item.
if (groupId == 0) {
mDefaultVolumeItem = volumeItem;
setupDefaultListItem();
setupDefaultCarVolumeItem();
}
}
// If list is already initiated, update its content.
if (mPagedListAdapter != null) {
mPagedListAdapter.notifyDataSetChanged();
if (mVolumeItemsAdapter != null) {
mVolumeItemsAdapter.notifyDataSetChanged();
}
mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
} catch (CarNotConnectedException e) {
@@ -184,15 +177,15 @@ public class CarVolumeDialogImpl implements VolumeDialog {
}
};
private void setupDefaultListItem() {
private void setupDefaultCarVolumeItem() {
mDefaultVolumeItem.defaultItem = true;
addSeekbarListItem(mDefaultVolumeItem, /* volumeGroupId = */0,
addCarVolumeListItem(mDefaultVolumeItem, /* volumeGroupId = */0,
R.drawable.car_ic_keyboard_arrow_down, new ExpandIconListener()
);
}
public CarVolumeDialogImpl(Context context) {
mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
mContext = context;
mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mCar = Car.createCar(mContext, mServiceConnection);
}
@@ -238,7 +231,7 @@ public class CarVolumeDialogImpl implements VolumeDialog {
private void initDialog() {
loadAudioUsageItems();
mVolumeLineItems.clear();
mCarVolumeLineItems.clear();
mDialog = new CustomDialog(mContext);
mHovering = false;
@@ -246,7 +239,6 @@ public class CarVolumeDialogImpl implements VolumeDialog {
mExpanded = false;
mWindow = mDialog.getWindow();
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -263,10 +255,11 @@ public class CarVolumeDialogImpl implements VolumeDialog {
lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
lp.windowAnimations = -1;
mWindow.setAttributes(lp);
mWindow.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mDialog.setContentView(R.layout.car_volume_dialog);
mWindow.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mDialog.setCanceledOnTouchOutside(true);
mDialog.setContentView(R.layout.car_volume_dialog);
mDialog.setOnShowListener(dialog -> {
mListView.setTranslationY(-mListView.getHeight());
mListView.setAlpha(0);
@@ -277,7 +270,7 @@ public class CarVolumeDialogImpl implements VolumeDialog {
.setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
.start();
});
mListView = (PagedListView) mWindow.findViewById(R.id.volume_list);
mListView = mWindow.findViewById(R.id.volume_list);
mListView.setOnHoverListener((v, event) -> {
int action = event.getActionMasked();
mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
@@ -286,10 +279,9 @@ public class CarVolumeDialogImpl implements VolumeDialog {
return true;
});
mPagedListAdapter = new ListItemAdapter(mContext, new ListProvider(mVolumeLineItems),
BackgroundStyle.PANEL);
mListView.setAdapter(mPagedListAdapter);
mListView.setMaxPages(PagedListView.UNLIMITED_PAGES);
mVolumeItemsAdapter = new CarVolumeItemAdapter(mContext, mCarVolumeLineItems);
mListView.setAdapter(mVolumeItemsAdapter);
mListView.setLayoutManager(new LinearLayoutManager(mContext));
}
@@ -302,13 +294,13 @@ public class CarVolumeDialogImpl implements VolumeDialog {
mHandler.removeMessages(H.DISMISS);
rescheduleTimeoutH();
// Refresh the data set before showing.
mPagedListAdapter.notifyDataSetChanged();
mVolumeItemsAdapter.notifyDataSetChanged();
if (mShowing) {
return;
}
mShowing = true;
if (mVolumeLineItems.isEmpty()) {
setupDefaultListItem();
if (mCarVolumeLineItems.isEmpty()) {
setupDefaultCarVolumeItem();
}
mDialog.show();
Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
@@ -421,40 +413,41 @@ public class CarVolumeDialogImpl implements VolumeDialog {
return result;
}
private SeekbarListItem addSeekbarListItem(VolumeItem volumeItem,
int volumeGroupId,
private CarVolumeItem addCarVolumeListItem(VolumeItem volumeItem, int volumeGroupId,
int supplementalIconId,
@Nullable View.OnClickListener supplementalIconOnClickListener) {
SeekbarListItem listItem = new SeekbarListItem(mContext);
listItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId));
CarVolumeItem carVolumeItem = new CarVolumeItem();
carVolumeItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId));
int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
int progress = getSeekbarValue(mCarAudioManager, volumeGroupId);
listItem.setProgress(progress);
listItem.setOnSeekBarChangeListener(new CarVolumeDialogImpl
.VolumeSeekBarChangeListener(volumeGroupId, mCarAudioManager));
carVolumeItem.setProgress(progress);
carVolumeItem.setOnSeekBarChangeListener(
new CarVolumeDialogImpl.VolumeSeekBarChangeListener(volumeGroupId,
mCarAudioManager));
Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
primaryIcon.mutate().setTint(color);
listItem.setPrimaryActionIcon(primaryIcon);
carVolumeItem.setPrimaryIcon(primaryIcon);
if (supplementalIconId != 0) {
Drawable supplementalIcon = mContext.getResources().getDrawable(supplementalIconId);
supplementalIcon.mutate().setTint(color);
listItem.setSupplementalIcon(supplementalIcon, true);
listItem.setSupplementalIconListener(supplementalIconOnClickListener);
carVolumeItem.setSupplementalIcon(supplementalIcon,
/* showSupplementalIconDivider= */ true);
carVolumeItem.setSupplementalIconListener(supplementalIconOnClickListener);
} else {
listItem.setSupplementalEmptyIcon(true);
listItem.setSupplementalIconListener(null);
carVolumeItem.setSupplementalIcon(/* drawable= */ null,
/* showSupplementalIconDivider= */ false);
}
mVolumeLineItems.add(listItem);
volumeItem.listItem = listItem;
mCarVolumeLineItems.add(carVolumeItem);
volumeItem.carVolumeItem = carVolumeItem;
volumeItem.progress = progress;
return listItem;
return carVolumeItem;
}
private VolumeItem findVolumeItem(SeekbarListItem targetItem) {
private VolumeItem findVolumeItem(CarVolumeItem targetItem) {
for (int i = 0; i < mVolumeItems.size(); ++i) {
VolumeItem volumeItem = mVolumeItems.valueAt(i);
if (volumeItem.listItem == targetItem) {
if (volumeItem.carVolumeItem == targetItem) {
return volumeItem;
}
}
@@ -463,7 +456,7 @@ public class CarVolumeDialogImpl implements VolumeDialog {
private void cleanupAudioManager() {
mCarAudioManager.unregisterCarVolumeCallback(mVolumeChangeCallback);
mVolumeLineItems.clear();
mCarVolumeLineItems.clear();
mCarAudioManager = null;
}
@@ -474,8 +467,9 @@ public class CarVolumeDialogImpl implements VolumeDialog {
private int rank;
private boolean defaultItem = false;
private @DrawableRes int icon;
private SeekbarListItem listItem;
@DrawableRes
private int icon;
private CarVolumeItem carVolumeItem;
private int progress;
}
@@ -554,9 +548,9 @@ public class CarVolumeDialogImpl implements VolumeDialog {
// Adding the items which are not coming from the default item.
VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
if (volumeItem.defaultItem) {
updateDefaultVolumeItem(volumeItem.listItem);
updateDefaultVolumeItem(volumeItem.carVolumeItem);
} else {
addSeekbarListItem(volumeItem, groupId, 0, null);
addCarVolumeListItem(volumeItem, groupId, 0, null);
}
}
inAnimator = AnimatorInflater.loadAnimator(
@@ -564,14 +558,14 @@ public class CarVolumeDialogImpl implements VolumeDialog {
} else {
// Only keeping the default stream if it is not expended.
Iterator itr = mVolumeLineItems.iterator();
Iterator itr = mCarVolumeLineItems.iterator();
while (itr.hasNext()) {
SeekbarListItem seekbarListItem = (SeekbarListItem) itr.next();
VolumeItem volumeItem = findVolumeItem(seekbarListItem);
CarVolumeItem carVolumeItem = (CarVolumeItem) itr.next();
VolumeItem volumeItem = findVolumeItem(carVolumeItem);
if (!volumeItem.defaultItem) {
itr.remove();
} else {
updateDefaultVolumeItem(seekbarListItem);
updateDefaultVolumeItem(carVolumeItem);
}
}
inAnimator = AnimatorInflater.loadAnimator(
@@ -590,22 +584,22 @@ public class CarVolumeDialogImpl implements VolumeDialog {
}
animators.setTarget(mExpandIcon);
animators.start();
mPagedListAdapter.notifyDataSetChanged();
mVolumeItemsAdapter.notifyDataSetChanged();
}
private void updateDefaultVolumeItem(SeekbarListItem seekbarListItem){
VolumeItem volumeItem = findVolumeItem(seekbarListItem);
private void updateDefaultVolumeItem(CarVolumeItem carVolumeItem) {
VolumeItem volumeItem = findVolumeItem(carVolumeItem);
// When volume dialog is expanded or collapsed the default list item is never
// reset. Whereas all other list items are removed when the dialog is collapsed and then
// added when the dialog is expanded using {@link CarVolumeDialogImpl#addSeekbarListItem}.
// added when the dialog is expanded using {@link CarVolumeDialogImpl#addCarVolumeListItem}.
// This sets the progressbar and the tint color of icons for all items other than default
// if they were changed. For default list item it should be done manually here.
int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
primaryIcon.mutate().setTint(color);
volumeItem.listItem.setPrimaryActionIcon(primaryIcon);
volumeItem.listItem.setProgress(volumeItem.progress);
volumeItem.carVolumeItem.setPrimaryIcon(primaryIcon);
volumeItem.carVolumeItem.setProgress(volumeItem.progress);
}
private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
@@ -646,4 +640,4 @@ public class CarVolumeDialogImpl implements VolumeDialog {
public void onStopTrackingTouch(SeekBar seekBar) {
}
}
}
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.volume;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.android.systemui.R;
/** Holds all related data to represent a volume group. */
public class CarVolumeItem {
private boolean mIsDirty;
private Drawable mPrimaryIcon;
private Drawable mSupplementalIcon;
private View.OnClickListener mSupplementalIconOnClickListener;
private boolean mShowSupplementalIconDivider;
private int mMax;
private int mProgress;
private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener;
public CarVolumeItem() {
mIsDirty = true;
}
/**
* Called when {@link CarVolumeItem} is bound to its ViewHolder.
*/
void bind(CarVolumeItemViewHolder viewHolder) {
if (mIsDirty) {
viewHolder.bind(/* carVolumeItem= */ this);
mIsDirty = false;
}
}
/** Sets progress of seekbar. */
public void setProgress(int progress) {
mProgress = progress;
mIsDirty = true;
}
/** Sets max value of seekbar. */
public void setMax(int max) {
mMax = max;
mIsDirty = true;
}
/** Sets {@link SeekBar.OnSeekBarChangeListener}. */
public void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) {
mOnSeekBarChangeListener = listener;
mIsDirty = true;
}
/** Sets the primary icon. */
public void setPrimaryIcon(Drawable drawable) {
mPrimaryIcon = drawable;
mIsDirty = true;
}
/** Sets the supplemental icon and the visibility of the supplemental icon divider. */
public void setSupplementalIcon(Drawable drawable, boolean showSupplementalIconDivider) {
mSupplementalIcon = drawable;
mShowSupplementalIconDivider = showSupplementalIconDivider;
mIsDirty = true;
}
/** Sets {@code OnClickListener} for the supplemental icon. */
public void setSupplementalIconListener(View.OnClickListener listener) {
mSupplementalIconOnClickListener = listener;
mIsDirty = true;
}
/** Defines the view holder which shows the information held by {@link CarVolumeItem}. */
public static class CarVolumeItemViewHolder extends RecyclerView.ViewHolder {
private SeekBar mSeekBar;
private ImageView mPrimaryIcon;
private View mSupplementalIconDivider;
private ImageView mSupplementalIcon;
public CarVolumeItemViewHolder(@NonNull View itemView) {
super(itemView);
mSeekBar = itemView.findViewById(R.id.seek_bar);
mPrimaryIcon = itemView.findViewById(R.id.primary_icon);
mSupplementalIcon = itemView.findViewById(R.id.supplemental_icon);
mSupplementalIconDivider = itemView.findViewById(R.id.supplemental_icon_divider);
}
/**
* Binds {@link CarVolumeItem} to the {@link CarVolumeItemViewHolder}.
*/
void bind(CarVolumeItem carVolumeItem) {
// Progress bar
mSeekBar.setMax(carVolumeItem.mMax);
mSeekBar.setProgress(carVolumeItem.mProgress);
mSeekBar.setOnSeekBarChangeListener(carVolumeItem.mOnSeekBarChangeListener);
// Primary icon
mPrimaryIcon.setVisibility(View.VISIBLE);
mPrimaryIcon.setImageDrawable(carVolumeItem.mPrimaryIcon);
// Supplemental icon
mSupplementalIcon.setVisibility(View.VISIBLE);
mSupplementalIconDivider.setVisibility(
carVolumeItem.mShowSupplementalIconDivider ? View.VISIBLE : View.INVISIBLE);
mSupplementalIcon.setImageDrawable(carVolumeItem.mSupplementalIcon);
mSupplementalIcon.setOnClickListener(
carVolumeItem.mSupplementalIconOnClickListener);
mSupplementalIcon.setClickable(
carVolumeItem.mSupplementalIconOnClickListener != null);
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.volume;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;
import com.android.systemui.R;
import java.util.List;
/** The {@link RecyclerView.Adapter} to show the volume items in the sysUI volume dialog. */
public class CarVolumeItemAdapter extends
RecyclerView.Adapter<CarVolumeItem.CarVolumeItemViewHolder> {
private final Context mContext;
private final List<CarVolumeItem> mItems;
public CarVolumeItemAdapter(Context context, List<CarVolumeItem> items) {
mContext = context;
mItems = items;
}
@Override
public CarVolumeItem.CarVolumeItemViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.car_volume_item, parent, false);
return new CarVolumeItem.CarVolumeItemViewHolder(view);
}
@Override
public void onBindViewHolder(CarVolumeItem.CarVolumeItemViewHolder holder, int position) {
mItems.get(position).bind(holder);
}
@Override
public int getItemCount() {
return mItems.size();
}
}