diff options
| author | 2017-04-07 17:19:54 -0700 | |
|---|---|---|
| committer | 2017-06-28 14:32:28 -0700 | |
| commit | 54daefe3aa8dcdee149ce95fd4f8ecf60632c9f1 (patch) | |
| tree | b894c08719d82aecdfde1809531dba15741a783f | |
| parent | cbbb27bce21844157e57cdb40d665e28f1eb63e0 (diff) | |
Use custom QS fragment for auto use-case.
Use a custom QS fragment if the UI mode is car. This fragment disables
the quick settings row and expansion. Remove the config options that
used to have disabled this in the phone QSFragment.
To accomplish this, introduce a new QSFooter interface. The old
QSFooter.java now implements this.
Test: boot on phone and Android Auto headunit
Bug: 33210494
Change-Id: I5accc2d27d6725380ca5e271d332a03991c9419b
25 files changed, 1186 insertions, 523 deletions
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java index d57124381c1f..a648345e9c04 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java @@ -31,9 +31,9 @@ import com.android.systemui.plugins.qs.QS.HeightListener; @DependsOn(target = HeightListener.class) public interface QS extends FragmentBase { - public static final String ACTION = "com.android.systemui.action.PLUGIN_QS"; + String ACTION = "com.android.systemui.action.PLUGIN_QS"; - public static final int VERSION = 6; + int VERSION = 6; String TAG = "QS"; @@ -66,8 +66,8 @@ public interface QS extends FragmentBase { } @ProvidesInterface(version = HeightListener.VERSION) - public interface HeightListener { - public static final int VERSION = 1; + interface HeightListener { + int VERSION = 1; void onQsHeightChanged(); } diff --git a/packages/SystemUI/res/drawable/car_qs_background_primary.xml b/packages/SystemUI/res/drawable/car_qs_background_primary.xml new file mode 100644 index 000000000000..0f77987bb7ce --- /dev/null +++ b/packages/SystemUI/res/drawable/car_qs_background_primary.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> +<inset xmlns:android="http://schemas.android.com/apk/res/android"> + <shape> + <solid android:color="?android:attr/colorPrimaryDark"/> + </shape> +</inset> diff --git a/packages/SystemUI/res/layout/car_qs_footer.xml b/packages/SystemUI/res/layout/car_qs_footer.xml new file mode 100644 index 000000000000..2ef3b05f0565 --- /dev/null +++ b/packages/SystemUI/res/layout/car_qs_footer.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> +<!-- extends RelativeLayout --> +<com.android.systemui.qs.car.CarQSFooter + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/qs_footer" + android:layout_width="match_parent" + android:layout_height="@dimen/qs_footer_height" + android:baselineAligned="false" + android:clickable="false" + android:clipChildren="false" + android:clipToPadding="false" + android:paddingBottom="16dp" + android:paddingTop="16dp" + android:paddingEnd="32dp" + android:paddingStart="32dp" + android:gravity="center_vertical" + android:orientation="horizontal"> + + <com.android.systemui.statusbar.phone.MultiUserSwitch + android:id="@+id/multi_user_switch" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + android:layout_width="48dp" + android:layout_height="48dp" + android:background="@drawable/ripple_drawable" + android:focusable="true"> + + <ImageView + android:id="@+id/multi_user_avatar" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center" + android:scaleType="centerInside"/> + </com.android.systemui.statusbar.phone.MultiUserSwitch> + + <com.android.systemui.statusbar.phone.SettingsButton + android:id="@+id/settings_button" + android:layout_alignParentEnd="true" + android:layout_centerVertical="true" + android:layout_width="48dp" + android:layout_height="48dp" + android:background="@drawable/ripple_drawable" + android:contentDescription="@string/accessibility_quick_settings_settings" + android:scaleType="centerCrop" + android:src="@drawable/ic_settings_16dp" + android:tint="?android:attr/colorForeground" + style="@android:style/Widget.Material.Button.Borderless" /> + +</com.android.systemui.qs.car.CarQSFooter> diff --git a/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml new file mode 100644 index 000000000000..d1f7ff83db93 --- /dev/null +++ b/packages/SystemUI/res/layout/car_qs_panel.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/quick_settings_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/car_qs_background_primary" + android:orientation="vertical" + android:elevation="4dp"> + + <include layout="@layout/car_status_bar_header" /> + <include layout="@layout/car_qs_footer" /> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/car_status_bar_header.xml b/packages/SystemUI/res/layout/car_status_bar_header.xml new file mode 100644 index 000000000000..158907e03541 --- /dev/null +++ b/packages/SystemUI/res/layout/car_status_bar_header.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> +<!-- Extends RelativeLayout --> +<com.android.systemui.qs.car.CarStatusBarHeader + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:id="@+id/header" + android:layout_width="match_parent" + android:layout_height="@dimen/car_qs_header_system_icons_area_height" + android:paddingStart="8dp" + android:paddingEnd="8dp" > + + <include + layout="@layout/system_icons" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" /> + + <com.android.systemui.statusbar.policy.Clock + android:id="@+id/clock" + android:textAppearance="@style/TextAppearance.StatusBar.Clock" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_alignParentEnd="true" + android:layout_centerVertical="true" + android:singleLine="true" + android:paddingStart="@dimen/status_bar_clock_starting_padding" + android:paddingEnd="@dimen/status_bar_clock_end_padding" + systemui:showDark="false" /> +</com.android.systemui.qs.car.CarStatusBarHeader> diff --git a/packages/SystemUI/res/layout/qs_footer.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml index db39905cf52a..43e88ba32736 100644 --- a/packages/SystemUI/res/layout/qs_footer.xml +++ b/packages/SystemUI/res/layout/qs_footer_impl.xml @@ -15,10 +15,10 @@ ** limitations under the License. --> -<!-- Extends RelativeLayout --> -<com.android.systemui.qs.QSFooter +<!-- Extends FrameLayout --> +<com.android.systemui.qs.QSFooterImpl xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/header" + android:id="@+id/qs_footer" android:layout_width="match_parent" android:layout_height="48dp" android:baselineAligned="false" @@ -114,4 +114,4 @@ android:padding="14dp" /> </LinearLayout> -</com.android.systemui.qs.QSFooter> +</com.android.systemui.qs.QSFooterImpl> diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml index 87101e4b3d14..5541f3de8e7c 100644 --- a/packages/SystemUI/res/layout/qs_panel.xml +++ b/packages/SystemUI/res/layout/qs_panel.xml @@ -32,8 +32,7 @@ <include layout="@layout/quick_status_bar_expanded_header" /> - <include android:id="@+id/qs_footer" - layout="@layout/qs_footer" /> + <include layout="@layout/qs_footer_impl" /> <include android:id="@+id/qs_detail" layout="@layout/qs_detail" /> diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index 2ff626aa89a9..e8b418cd902b 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -18,7 +18,6 @@ <!-- Extends RelativeLayout --> <com.android.systemui.qs.QuickStatusBarHeader xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/header" android:layout_width="match_parent" android:layout_height="@dimen/status_bar_header_height" @@ -31,46 +30,7 @@ android:paddingEnd="0dp" android:paddingStart="0dp"> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="32dp" - android:layout_alignParentEnd="true" - android:clipChildren="false" - android:clipToPadding="false" - android:gravity="center" - android:paddingStart="16dp" - android:paddingEnd="16dp" - android:orientation="horizontal"> - - - <com.android.keyguard.CarrierText - android:id="@+id/qs_carrier_text" - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:gravity="center_vertical|start" - android:ellipsize="marquee" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textColor="?android:attr/textColorPrimary" - android:singleLine="true" /> - - <com.android.systemui.BatteryMeterView android:id="@+id/battery" - android:layout_height="match_parent" - android:layout_width="wrap_content" - /> - - <com.android.systemui.statusbar.policy.Clock - android:id="@+id/clock" - android:textAppearance="@style/TextAppearance.StatusBar.Clock" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:singleLine="true" - android:paddingStart="@dimen/status_bar_clock_starting_padding" - android:paddingEnd="@dimen/status_bar_clock_end_padding" - android:gravity="center_vertical|start" - systemui:showDark="false" - /> - </LinearLayout> + <include layout="@layout/quick_status_bar_header_system_icons" /> <com.android.systemui.qs.QuickQSPanel android:id="@+id/quick_qs_panel" diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml new file mode 100644 index 000000000000..c6dbd18a7d12 --- /dev/null +++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** Copyright 2017, 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. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="@dimen/qs_header_system_icons_area_height" + android:layout_alignParentEnd="true" + android:clipChildren="false" + android:clipToPadding="false" + android:gravity="center" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:orientation="horizontal"> + + + <com.android.keyguard.CarrierText + android:id="@+id/qs_carrier_text" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:gravity="center_vertical|start" + android:ellipsize="marquee" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:attr/textColorPrimary" + android:singleLine="true" /> + + <com.android.systemui.BatteryMeterView android:id="@+id/battery" + android:layout_height="match_parent" + android:layout_width="wrap_content" + /> + + <com.android.systemui.statusbar.policy.Clock + android:id="@+id/clock" + android:textAppearance="@style/TextAppearance.StatusBar.Clock" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:singleLine="true" + android:paddingStart="@dimen/status_bar_clock_starting_padding" + android:paddingEnd="@dimen/status_bar_clock_end_padding" + android:gravity="center_vertical|start" + systemui:showDark="false" + /> +</LinearLayout> diff --git a/packages/SystemUI/res/values-car/dimens.xml b/packages/SystemUI/res/values-car/dimens.xml new file mode 100644 index 000000000000..b2e7bd1b881e --- /dev/null +++ b/packages/SystemUI/res/values-car/dimens.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (c) 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +--> +<resources> + <!-- The height of the quick settings footer that holds the user switcher, settings icon, + etc. in the car setting.--> + <dimen name="qs_footer_height">74dp</dimen> +</resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 2ad6f2da7fb0..c0068d3b2957 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -316,26 +316,6 @@ <!-- Whether or not a background should be drawn behind a notification. --> <bool name="config_drawNotificationBackground">true</bool> - <!-- Whether or not the edit icon on the quick settings header is shown. --> - <bool name="config_showQuickSettingsEditingIcon">true</bool> - - <!-- Whether or not the multi-user switcher should be visible even if the quick settings are - not expanded. If there are not multiple users on the system, the switcher will still - hide itself. --> - <bool name="config_alwaysShowMultiUserSwitcher">false</bool> - - <!-- Whether or not the expand indicator is visible for manually expanding the quick settings - panel. --> - <bool name="config_showQuickSettingsExpandIndicator">true</bool> - - <!-- Whether or not to display the row of quick settings icons separate from the full quick - settings panel. --> - <bool name="config_showQuickSettingsRow">true</bool> - - <!-- Whether or not the quick settings should be revealed on an overscroll of the - notifications panel. --> - <bool name="config_enableQuickSettingsOverscrollExpansion">true</bool> - <!-- Whether or the notifications can be shown and dismissed with a drag. --> <bool name="config_enableNotificationShadeDrag">true</bool> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 93d2072e955c..19bafb72ae82 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -189,6 +189,23 @@ <!-- Height of the status bar header bar --> <dimen name="status_bar_header_height">124dp</dimen> + <!-- Height of the status bar header bar in the car setting. --> + <dimen name="car_status_bar_header_height">128dp</dimen> + + <!-- The bottom padding of the status bar header. --> + <dimen name="status_bar_header_padding_bottom">48dp</dimen> + + <!-- The height of the container that holds the system icons in the quick settings header. --> + <dimen name="qs_header_system_icons_area_height">32dp</dimen> + + <!-- The height of the container that holds the system icons in the quick settings header in the + car setting. --> + <dimen name="car_qs_header_system_icons_area_height">54dp</dimen> + + <!-- The height of the quick settings footer that holds the user switcher, settings icon, + etc. --> + <dimen name="qs_footer_height">48dp</dimen> + <!-- Height of the status bar header bar when expanded --> <dimen name="status_bar_header_height_expanded">124dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java index ed57c043a109..33b5268e03e1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java @@ -38,7 +38,7 @@ public class QSContainerImpl extends FrameLayout { protected View mHeader; protected float mQsExpansion; private QSCustomizer mQSCustomizer; - private QSFooter mQSFooter; + private View mQSFooter; private float mFullElevation; public QSContainerImpl(Context context, AttributeSet attrs) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java index 488fc03032fd..3f3cea2eaa17 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Android Open Source Project + * Copyright (C) 2017 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. @@ -13,426 +13,60 @@ * See the License for the specific language governing permissions and * limitations under the License */ - package com.android.systemui.qs; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_DATE; - -import android.app.ActivityManager; -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.PorterDuff.Mode; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.RippleDrawable; -import android.os.UserManager; -import android.provider.AlarmClock; import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; -import android.util.AttributeSet; import android.view.View; -import android.view.View.OnClickListener; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto; -import com.android.keyguard.KeyguardStatusView; -import com.android.settingslib.Utils; -import com.android.systemui.Dependency; -import com.android.systemui.FontSizeUtils; -import com.android.systemui.R; -import com.android.systemui.R.dimen; -import com.android.systemui.R.id; -import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.qs.TouchAnimator.Builder; -import com.android.systemui.qs.TouchAnimator.Listener; -import com.android.systemui.qs.TouchAnimator.ListenerAdapter; -import com.android.systemui.statusbar.phone.ExpandableIndicator; -import com.android.systemui.statusbar.phone.MultiUserSwitch; -import com.android.systemui.statusbar.phone.SettingsButton; -import com.android.systemui.statusbar.policy.DeviceProvisionedController; -import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener; -import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; -import com.android.systemui.statusbar.policy.NextAlarmController; -import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; -import com.android.systemui.statusbar.policy.UserInfoController; -import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener; -import com.android.systemui.tuner.TunerService; - -public class QSFooter extends FrameLayout implements - NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener, - SignalCallback { - private static final float EXPAND_INDICATOR_THRESHOLD = .93f; - - private ActivityStarter mActivityStarter; - private NextAlarmController mNextAlarmController; - private UserInfoController mUserInfoController; - private SettingsButton mSettingsButton; - protected View mSettingsContainer; - - private TextView mAlarmStatus; - private View mAlarmStatusCollapsed; - private View mDate; - - private QSPanel mQsPanel; - - private boolean mExpanded; - private boolean mAlarmShowing; - - protected ExpandableIndicator mExpandIndicator; - - private boolean mListening; - private AlarmManager.AlarmClockInfo mNextAlarm; - - private boolean mShowEmergencyCallsOnly; - protected MultiUserSwitch mMultiUserSwitch; - private ImageView mMultiUserAvatar; - private boolean mAlwaysShowMultiUserSwitch; - - protected TouchAnimator mSettingsAlpha; - private float mExpansionAmount; - - protected View mEdit; - private boolean mShowEditIcon; - private TouchAnimator mAnimator; - private View mDateTimeGroup; - private boolean mKeyguardShowing; - private TouchAnimator mAlarmAnimator; - - public QSFooter(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - Resources res = getResources(); - - mShowEditIcon = res.getBoolean(R.bool.config_showQuickSettingsEditingIcon); - - mEdit = findViewById(android.R.id.edit); - mEdit.setVisibility(mShowEditIcon ? VISIBLE : GONE); - - if (mShowEditIcon) { - findViewById(android.R.id.edit).setOnClickListener(view -> - Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> - mQsPanel.showEdit(view))); - } - - mDateTimeGroup = findViewById(id.date_time_alarm_group); - mDate = findViewById(R.id.date); - - mExpandIndicator = findViewById(R.id.expand_indicator); - mExpandIndicator.setVisibility( - res.getBoolean(R.bool.config_showQuickSettingsExpandIndicator) - ? VISIBLE : GONE); - - mSettingsButton = findViewById(R.id.settings_button); - mSettingsContainer = findViewById(R.id.settings_button_container); - mSettingsButton.setOnClickListener(this); - - mAlarmStatusCollapsed = findViewById(R.id.alarm_status_collapsed); - mAlarmStatus = findViewById(R.id.alarm_status); - mDateTimeGroup.setOnClickListener(this); - - mMultiUserSwitch = findViewById(R.id.multi_user_switch); - mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar); - mAlwaysShowMultiUserSwitch = res.getBoolean(R.bool.config_alwaysShowMultiUserSwitcher); - - // RenderThread is doing more harm than good when touching the header (to expand quick - // settings), so disable it for this view - ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true); - ((RippleDrawable) mExpandIndicator.getBackground()).setForceSoftware(true); - - updateResources(); - - mNextAlarmController = Dependency.get(NextAlarmController.class); - mUserInfoController = Dependency.get(UserInfoController.class); - mActivityStarter = Dependency.get(ActivityStarter.class); - addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, - oldBottom) -> updateAnimator(right - left)); - } - - private void updateAnimator(int width) { - int numTiles = QuickQSPanel.getNumQuickTiles(mContext); - int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size) - - mContext.getResources().getDimensionPixelSize(dimen.qs_quick_tile_padding); - int remaining = (width - numTiles * size) / (numTiles - 1); - int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space); - - mAnimator = new Builder() - .addFloat(mSettingsContainer, "translationX", -(remaining - defSpace), 0) - .addFloat(mSettingsButton, "rotation", -120, 0) - .build(); - if (mAlarmShowing) { - mAlarmAnimator = new Builder().addFloat(mDate, "alpha", 1, 0) - .addFloat(mDateTimeGroup, "translationX", 0, -mDate.getWidth()) - .addFloat(mAlarmStatus, "alpha", 0, 1) - .setListener(new ListenerAdapter() { - @Override - public void onAnimationAtStart() { - mAlarmStatus.setVisibility(View.GONE); - } - - @Override - public void onAnimationStarted() { - mAlarmStatus.setVisibility(View.VISIBLE); - } - }).build(); - } else { - mAlarmAnimator = null; - mAlarmStatus.setVisibility(View.GONE); - mDate.setAlpha(1); - mDateTimeGroup.setTranslationX(0); - } - setExpansion(mExpansionAmount); - } - - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - updateResources(); - } - - @Override - public void onRtlPropertiesChanged(int layoutDirection) { - super.onRtlPropertiesChanged(layoutDirection); - updateResources(); - } - - private void updateResources() { - FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size); - - updateSettingsAnimator(); - } - - private void updateSettingsAnimator() { - mSettingsAlpha = createSettingsAlphaAnimator(); - - final boolean isRtl = isLayoutRtl(); - if (isRtl && mDate.getWidth() == 0) { - mDate.addOnLayoutChangeListener(new OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, - int oldLeft, int oldTop, int oldRight, int oldBottom) { - mDate.setPivotX(getWidth()); - mDate.removeOnLayoutChangeListener(this); - } - }); - } else { - mDate.setPivotX(isRtl ? mDate.getWidth() : 0); - } - } +/** + * The bottom footer of the quick settings panel. + */ +public interface QSFooter { + /** + * Sets the given {@link QSPanel} to be the one that will display the quick settings. + */ + void setQSPanel(@Nullable QSPanel panel); + + /** + * Sets whether or not the footer should be visible. + * + * @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE} or {@link View#GONE}. + * @see View#setVisibility(int) + */ + void setVisibility(int visibility); + + /** + * Sets whether the footer is in an expanded state. + */ + void setExpanded(boolean expanded); + + /** + * Returns the full height of the footer. + */ + int getHeight(); + + /** + * Sets the percentage amount that the quick settings has been expanded. + * + * @param expansion A value from 1 to 0 that indicates how much the quick settings have been + * expanded. 1 is fully expanded. + */ + void setExpansion(float expansion); + + /** + * Sets whether or not this footer should set itself to listen for changes in any callbacks + * that it has implemented. + */ + void setListening(boolean listening); + + /** + * Sets whether or not the keyguard is currently being shown. + */ + void setKeyguardShowing(boolean keyguardShowing); + + /** + * Returns the {@link View} that should expand the quick settings when clicked. + */ @Nullable - private TouchAnimator createSettingsAlphaAnimator() { - // If the settings icon is not shown and the user switcher is always shown, then there - // is nothing to animate. - if (!mShowEditIcon && mAlwaysShowMultiUserSwitch) { - return null; - } - - TouchAnimator.Builder animatorBuilder = new TouchAnimator.Builder(); - animatorBuilder.setStartDelay(QSAnimator.EXPANDED_TILE_DELAY); - - if (mShowEditIcon) { - animatorBuilder.addFloat(mEdit, "alpha", 0, 1); - } - - if (!mAlwaysShowMultiUserSwitch) { - animatorBuilder.addFloat(mMultiUserSwitch, "alpha", 0, 1); - } - - return animatorBuilder.build(); - } - - public void setKeyguardShowing(boolean keyguardShowing) { - mKeyguardShowing = keyguardShowing; - setExpansion(mExpansionAmount); - } - - public void setExpanded(boolean expanded) { - if (mExpanded == expanded) return; - mExpanded = expanded; - updateEverything(); - } - - @Override - public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { - mNextAlarm = nextAlarm; - if (nextAlarm != null) { - String alarmString = KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm); - mAlarmStatus.setText(alarmString); - mAlarmStatus.setContentDescription(mContext.getString( - R.string.accessibility_quick_settings_alarm, alarmString)); - mAlarmStatusCollapsed.setContentDescription(mContext.getString( - R.string.accessibility_quick_settings_alarm, alarmString)); - } - if (mAlarmShowing != (nextAlarm != null)) { - mAlarmShowing = nextAlarm != null; - updateAnimator(getWidth()); - updateEverything(); - } - } - - public void setExpansion(float headerExpansionFraction) { - mExpansionAmount = headerExpansionFraction; - if (mAnimator != null) mAnimator.setPosition(headerExpansionFraction); - if (mAlarmAnimator != null) mAlarmAnimator.setPosition( - mKeyguardShowing ? 0 : headerExpansionFraction); - - if (mSettingsAlpha != null) { - mSettingsAlpha.setPosition(headerExpansionFraction); - } - - updateAlarmVisibilities(); - - mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD); - } - - @Override - @VisibleForTesting - public void onDetachedFromWindow() { - setListening(false); - super.onDetachedFromWindow(); - } - - private void updateAlarmVisibilities() { - mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.GONE); - } - - public void setListening(boolean listening) { - if (listening == mListening) { - return; - } - mListening = listening; - updateListeners(); - } - - public View getExpandView() { - return findViewById(R.id.expand_indicator); - } - - public void updateEverything() { - post(() -> { - updateVisibilities(); - setClickable(false); - }); - } - - private void updateVisibilities() { - updateAlarmVisibilities(); - mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility( - TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE); - final boolean isDemo = UserManager.isDeviceInDemoMode(mContext); - - mMultiUserSwitch.setVisibility((mExpanded || mAlwaysShowMultiUserSwitch) - && mMultiUserSwitch.hasMultipleUsers() && !isDemo - ? View.VISIBLE : View.INVISIBLE); - - if (mShowEditIcon) { - mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE); - } - } - - private void updateListeners() { - if (mListening) { - mNextAlarmController.addCallback(this); - mUserInfoController.addCallback(this); - if (Dependency.get(NetworkController.class).hasVoiceCallingFeature()) { - Dependency.get(NetworkController.class).addEmergencyListener(this); - Dependency.get(NetworkController.class).addCallback(this); - } - } else { - mNextAlarmController.removeCallback(this); - mUserInfoController.removeCallback(this); - Dependency.get(NetworkController.class).removeEmergencyListener(this); - Dependency.get(NetworkController.class).removeCallback(this); - } - } - - public void setQSPanel(final QSPanel qsPanel) { - mQsPanel = qsPanel; - if (mQsPanel != null) { - mMultiUserSwitch.setQsPanel(qsPanel); - } - } - - @Override - public void onClick(View v) { - if (v == mSettingsButton) { - if (!Dependency.get(DeviceProvisionedController.class).isCurrentUserSetup()) { - // If user isn't setup just unlock the device and dump them back at SUW. - mActivityStarter.postQSRunnableDismissingKeyguard(() -> { }); - return; - } - MetricsLogger.action(mContext, - mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH - : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH); - if (mSettingsButton.isTunerClick()) { - Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> { - if (TunerService.isTunerEnabled(mContext)) { - TunerService.showResetRequest(mContext, () -> { - // Relaunch settings so that the tuner disappears. - startSettingsActivity(); - }); - } else { - Toast.makeText(getContext(), R.string.tuner_toast, - Toast.LENGTH_LONG).show(); - TunerService.setTunerEnabled(mContext, true); - } - startSettingsActivity(); - - }); - } else { - startSettingsActivity(); - } - } else if (v == mDateTimeGroup) { - Dependency.get(MetricsLogger.class).action(ACTION_QS_DATE, - mNextAlarm != null); - if (mNextAlarm != null) { - PendingIntent showIntent = mNextAlarm.getShowIntent(); - mActivityStarter.startPendingIntentDismissingKeyguard(showIntent); - } else { - mActivityStarter.postStartActivityDismissingKeyguard(new Intent( - AlarmClock.ACTION_SHOW_ALARMS), 0); - } - } - } - - private void startSettingsActivity() { - mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS), - true /* dismissShade */); - } - - @Override - public void setEmergencyCallsOnly(boolean show) { - boolean changed = show != mShowEmergencyCallsOnly; - if (changed) { - mShowEmergencyCallsOnly = show; - if (mExpanded) { - updateEverything(); - } - } - } - - @Override - public void onUserInfoChanged(String name, Drawable picture, String userAccount) { - if (picture != null && - UserManager.get(mContext).isGuestUser(ActivityManager.getCurrentUser())) { - picture = picture.getConstantState().newDrawable().mutate(); - picture.setColorFilter( - Utils.getColorAttr(mContext, android.R.attr.colorForeground), - Mode.SRC_IN); - } - mMultiUserAvatar.setImageDrawable(picture); - } + View getExpandView(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java new file mode 100644 index 000000000000..94da5f72be10 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.qs; + +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_DATE; + +import android.app.ActivityManager; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.PorterDuff.Mode; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.RippleDrawable; +import android.os.UserManager; +import android.provider.AlarmClock; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; +import android.util.AttributeSet; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto; +import com.android.keyguard.KeyguardStatusView; +import com.android.settingslib.Utils; +import com.android.systemui.Dependency; +import com.android.systemui.FontSizeUtils; +import com.android.systemui.R; +import com.android.systemui.R.dimen; +import com.android.systemui.R.id; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.qs.TouchAnimator.Builder; +import com.android.systemui.qs.TouchAnimator.Listener; +import com.android.systemui.qs.TouchAnimator.ListenerAdapter; +import com.android.systemui.statusbar.phone.ExpandableIndicator; +import com.android.systemui.statusbar.phone.MultiUserSwitch; +import com.android.systemui.statusbar.phone.SettingsButton; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener; +import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; +import com.android.systemui.statusbar.policy.NextAlarmController; +import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; +import com.android.systemui.statusbar.policy.UserInfoController; +import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener; +import com.android.systemui.tuner.TunerService; + +public class QSFooterImpl extends FrameLayout implements QSFooter, + NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener, + SignalCallback { + private static final float EXPAND_INDICATOR_THRESHOLD = .93f; + + private ActivityStarter mActivityStarter; + private NextAlarmController mNextAlarmController; + private UserInfoController mUserInfoController; + private SettingsButton mSettingsButton; + protected View mSettingsContainer; + + private TextView mAlarmStatus; + private View mAlarmStatusCollapsed; + private View mDate; + + private QSPanel mQsPanel; + + private boolean mExpanded; + private boolean mAlarmShowing; + + protected ExpandableIndicator mExpandIndicator; + + private boolean mListening; + private AlarmManager.AlarmClockInfo mNextAlarm; + + private boolean mShowEmergencyCallsOnly; + protected MultiUserSwitch mMultiUserSwitch; + private ImageView mMultiUserAvatar; + + protected TouchAnimator mSettingsAlpha; + private float mExpansionAmount; + + protected View mEdit; + private TouchAnimator mAnimator; + private View mDateTimeGroup; + private boolean mKeyguardShowing; + private TouchAnimator mAlarmAnimator; + + public QSFooterImpl(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + Resources res = getResources(); + + mEdit = findViewById(android.R.id.edit); + mEdit.setOnClickListener(view -> + Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> + mQsPanel.showEdit(view))); + + mDateTimeGroup = findViewById(id.date_time_alarm_group); + mDate = findViewById(R.id.date); + + mExpandIndicator = findViewById(R.id.expand_indicator); + mSettingsButton = findViewById(R.id.settings_button); + mSettingsContainer = findViewById(R.id.settings_button_container); + mSettingsButton.setOnClickListener(this); + + mAlarmStatusCollapsed = findViewById(R.id.alarm_status_collapsed); + mAlarmStatus = findViewById(R.id.alarm_status); + mDateTimeGroup.setOnClickListener(this); + + mMultiUserSwitch = findViewById(R.id.multi_user_switch); + mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar); + + // RenderThread is doing more harm than good when touching the header (to expand quick + // settings), so disable it for this view + ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true); + ((RippleDrawable) mExpandIndicator.getBackground()).setForceSoftware(true); + + updateResources(); + + mNextAlarmController = Dependency.get(NextAlarmController.class); + mUserInfoController = Dependency.get(UserInfoController.class); + mActivityStarter = Dependency.get(ActivityStarter.class); + addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, + oldBottom) -> updateAnimator(right - left)); + } + + private void updateAnimator(int width) { + int numTiles = QuickQSPanel.getNumQuickTiles(mContext); + int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size) + - mContext.getResources().getDimensionPixelSize(dimen.qs_quick_tile_padding); + int remaining = (width - numTiles * size) / (numTiles - 1); + int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space); + + mAnimator = new Builder() + .addFloat(mSettingsContainer, "translationX", -(remaining - defSpace), 0) + .addFloat(mSettingsButton, "rotation", -120, 0) + .build(); + if (mAlarmShowing) { + mAlarmAnimator = new Builder().addFloat(mDate, "alpha", 1, 0) + .addFloat(mDateTimeGroup, "translationX", 0, -mDate.getWidth()) + .addFloat(mAlarmStatus, "alpha", 0, 1) + .setListener(new ListenerAdapter() { + @Override + public void onAnimationAtStart() { + mAlarmStatus.setVisibility(View.GONE); + } + + @Override + public void onAnimationStarted() { + mAlarmStatus.setVisibility(View.VISIBLE); + } + }).build(); + } else { + mAlarmAnimator = null; + mAlarmStatus.setVisibility(View.GONE); + mDate.setAlpha(1); + mDateTimeGroup.setTranslationX(0); + } + setExpansion(mExpansionAmount); + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + updateResources(); + } + + @Override + public void onRtlPropertiesChanged(int layoutDirection) { + super.onRtlPropertiesChanged(layoutDirection); + updateResources(); + } + + private void updateResources() { + FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size); + + updateSettingsAnimator(); + } + + private void updateSettingsAnimator() { + mSettingsAlpha = createSettingsAlphaAnimator(); + + final boolean isRtl = isLayoutRtl(); + if (isRtl && mDate.getWidth() == 0) { + mDate.addOnLayoutChangeListener(new OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + mDate.setPivotX(getWidth()); + mDate.removeOnLayoutChangeListener(this); + } + }); + } else { + mDate.setPivotX(isRtl ? mDate.getWidth() : 0); + } + } + + @Nullable + private TouchAnimator createSettingsAlphaAnimator() { + return new TouchAnimator.Builder() + .addFloat(mEdit, "alpha", 0, 1) + .addFloat(mMultiUserSwitch, "alpha", 0, 1) + .build(); + } + + @Override + public void setKeyguardShowing(boolean keyguardShowing) { + mKeyguardShowing = keyguardShowing; + setExpansion(mExpansionAmount); + } + + @Override + public void setExpanded(boolean expanded) { + if (mExpanded == expanded) return; + mExpanded = expanded; + updateEverything(); + } + + @Override + public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { + mNextAlarm = nextAlarm; + if (nextAlarm != null) { + String alarmString = KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm); + mAlarmStatus.setText(alarmString); + mAlarmStatus.setContentDescription(mContext.getString( + R.string.accessibility_quick_settings_alarm, alarmString)); + mAlarmStatusCollapsed.setContentDescription(mContext.getString( + R.string.accessibility_quick_settings_alarm, alarmString)); + } + if (mAlarmShowing != (nextAlarm != null)) { + mAlarmShowing = nextAlarm != null; + updateAnimator(getWidth()); + updateEverything(); + } + } + + @Override + public void setExpansion(float headerExpansionFraction) { + mExpansionAmount = headerExpansionFraction; + if (mAnimator != null) mAnimator.setPosition(headerExpansionFraction); + if (mAlarmAnimator != null) mAlarmAnimator.setPosition( + mKeyguardShowing ? 0 : headerExpansionFraction); + + if (mSettingsAlpha != null) { + mSettingsAlpha.setPosition(headerExpansionFraction); + } + + updateAlarmVisibilities(); + + mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD); + } + + @Override + @VisibleForTesting + public void onDetachedFromWindow() { + setListening(false); + super.onDetachedFromWindow(); + } + + private void updateAlarmVisibilities() { + mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.GONE); + } + + @Override + public void setListening(boolean listening) { + if (listening == mListening) { + return; + } + mListening = listening; + updateListeners(); + } + + @Override + public View getExpandView() { + return findViewById(R.id.expand_indicator); + } + + public void updateEverything() { + post(() -> { + updateVisibilities(); + setClickable(false); + }); + } + + private void updateVisibilities() { + updateAlarmVisibilities(); + mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility( + TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE); + final boolean isDemo = UserManager.isDeviceInDemoMode(mContext); + + mMultiUserSwitch.setVisibility(mExpanded && mMultiUserSwitch.hasMultipleUsers() && !isDemo + ? View.VISIBLE : View.INVISIBLE); + + mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE); + } + + private void updateListeners() { + if (mListening) { + mNextAlarmController.addCallback(this); + mUserInfoController.addCallback(this); + if (Dependency.get(NetworkController.class).hasVoiceCallingFeature()) { + Dependency.get(NetworkController.class).addEmergencyListener(this); + Dependency.get(NetworkController.class).addCallback(this); + } + } else { + mNextAlarmController.removeCallback(this); + mUserInfoController.removeCallback(this); + Dependency.get(NetworkController.class).removeEmergencyListener(this); + Dependency.get(NetworkController.class).removeCallback(this); + } + } + + @Override + public void setQSPanel(final QSPanel qsPanel) { + mQsPanel = qsPanel; + if (mQsPanel != null) { + mMultiUserSwitch.setQsPanel(qsPanel); + } + } + + @Override + public void onClick(View v) { + if (v == mSettingsButton) { + if (!Dependency.get(DeviceProvisionedController.class).isCurrentUserSetup()) { + // If user isn't setup just unlock the device and dump them back at SUW. + mActivityStarter.postQSRunnableDismissingKeyguard(() -> { }); + return; + } + MetricsLogger.action(mContext, + mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH + : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH); + if (mSettingsButton.isTunerClick()) { + Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> { + if (TunerService.isTunerEnabled(mContext)) { + TunerService.showResetRequest(mContext, () -> { + // Relaunch settings so that the tuner disappears. + startSettingsActivity(); + }); + } else { + Toast.makeText(getContext(), R.string.tuner_toast, + Toast.LENGTH_LONG).show(); + TunerService.setTunerEnabled(mContext, true); + } + startSettingsActivity(); + + }); + } else { + startSettingsActivity(); + } + } else if (v == mDateTimeGroup) { + Dependency.get(MetricsLogger.class).action(ACTION_QS_DATE, + mNextAlarm != null); + if (mNextAlarm != null) { + PendingIntent showIntent = mNextAlarm.getShowIntent(); + mActivityStarter.startPendingIntentDismissingKeyguard(showIntent); + } else { + mActivityStarter.postStartActivityDismissingKeyguard(new Intent( + AlarmClock.ACTION_SHOW_ALARMS), 0); + } + } + } + + private void startSettingsActivity() { + mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS), + true /* dismissShade */); + } + + @Override + public void setEmergencyCallsOnly(boolean show) { + boolean changed = show != mShowEmergencyCallsOnly; + if (changed) { + mShowEmergencyCallsOnly = show; + if (mExpanded) { + updateEverything(); + } + } + } + + @Override + public void onUserInfoChanged(String name, Drawable picture, String userAccount) { + if (picture != null && + UserManager.get(mContext).isGuestUser(ActivityManager.getCurrentUser())) { + picture = picture.getConstantState().newDrawable().mutate(); + picture.setColorFilter( + Utils.getColorAttr(mContext, android.R.attr.colorForeground), + Mode.SRC_IN); + } + mMultiUserAvatar.setImageDrawable(picture); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index bb3672511c48..f9ccb50dfb41 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -16,11 +16,11 @@ package com.android.systemui.qs; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.annotation.Nullable; import android.app.Fragment; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; +import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.util.Log; import android.view.ContextThemeWrapper; @@ -80,14 +80,9 @@ public class QSFragment extends Fragment implements QS { mFooter = view.findViewById(R.id.qs_footer); mContainer = view.findViewById(id.quick_settings_container); - mQSDetail.setQsPanel(mQSPanel, mHeader, mFooter); - - // If the quick settings row is not shown, then there is no need for the animation from - // the row to the full QS panel. - if (getResources().getBoolean(R.bool.config_showQuickSettingsRow)) { - mQSAnimator = new QSAnimator(this, - mHeader.findViewById(R.id.quick_qs_panel), mQSPanel); - } + mQSDetail.setQsPanel(mQSPanel, mHeader, (View) mFooter); + mQSAnimator = new QSAnimator(this, + mHeader.findViewById(R.id.quick_qs_panel), mQSPanel); mQSCustomizer = view.findViewById(R.id.qs_customize); mQSCustomizer.setQs(this); @@ -131,6 +126,7 @@ public class QSFragment extends Fragment implements QS { public void setHasNotifications(boolean hasNotifications) { } + @Override public void setPanelView(HeightListener panelView) { mPanelView = panelView; } @@ -154,6 +150,7 @@ public class QSFragment extends Fragment implements QS { } } + @Override public boolean isCustomizing() { return mQSCustomizer.isCustomizing(); } @@ -195,15 +192,22 @@ public class QSFragment extends Fragment implements QS { return mQSCustomizer; } + @Override public boolean isShowingDetail() { return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail(); } + @Override public void setHeaderClickable(boolean clickable) { if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable); - mFooter.getExpandView().setClickable(clickable); + + View expandView = mFooter.getExpandView(); + if (expandView != null) { + expandView.setClickable(clickable); + } } + @Override public void setExpanded(boolean expanded) { if (DEBUG) Log.d(TAG, "setExpanded " + expanded); mQsExpanded = expanded; @@ -211,6 +215,7 @@ public class QSFragment extends Fragment implements QS { updateQsState(); } + @Override public void setKeyguardShowing(boolean keyguardShowing) { if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing); mKeyguardShowing = keyguardShowing; @@ -223,12 +228,14 @@ public class QSFragment extends Fragment implements QS { updateQsState(); } + @Override public void setOverscrolling(boolean stackScrollerOverscrolling) { if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling); mStackScrollerOverscrolling = stackScrollerOverscrolling; updateQsState(); } + @Override public void setListening(boolean listening) { if (DEBUG) Log.d(TAG, "setListening " + listening); mListening = listening; @@ -237,11 +244,13 @@ public class QSFragment extends Fragment implements QS { mQSPanel.setListening(mListening && mQsExpanded); } + @Override public void setHeaderListening(boolean listening) { mHeader.setListening(listening); mFooter.setListening(listening); } + @Override public void setQsExpansion(float expansion, float headerTranslation) { if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation); mContainer.setExpansion(expansion); @@ -269,6 +278,7 @@ public class QSFragment extends Fragment implements QS { mQSPanel.setClipBounds(mQsBounds); } + @Override public void animateHeaderSlidingIn(long delay) { if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn"); // If the QS is already expanded we don't need to slide in the header as it's already @@ -280,6 +290,7 @@ public class QSFragment extends Fragment implements QS { } } + @Override public void animateHeaderSlidingOut() { if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut"); mHeaderAnimating = true; @@ -300,7 +311,11 @@ public class QSFragment extends Fragment implements QS { @Override public void setExpandClickListener(OnClickListener onClickListener) { - mFooter.getExpandView().setOnClickListener(onClickListener); + View expandView = mFooter.getExpandView(); + + if (expandView != null) { + expandView.setOnClickListener(onClickListener); + } } @Override @@ -323,6 +338,7 @@ public class QSFragment extends Fragment implements QS { * The height this view wants to be. This is different from {@link #getMeasuredHeight} such that * during closing the detail panel, this already returns the smaller height. */ + @Override public int getDesiredHeight() { if (mQSCustomizer.isCustomizing()) { return getView().getHeight(); @@ -342,6 +358,7 @@ public class QSFragment extends Fragment implements QS { mContainer.setHeightOverride(desiredHeight); } + @Override public int getQsMinExpansionHeight() { return mHeader.getHeight(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 7ec07604fab5..0709e229bd4d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -58,8 +58,6 @@ public class QuickStatusBarHeader extends RelativeLayout { Resources res = getResources(); mHeaderQsPanel = findViewById(R.id.quick_qs_panel); - mHeaderQsPanel.setVisibility(res.getBoolean(R.bool.config_showQuickSettingsRow) - ? VISIBLE : GONE); // RenderThread is doing more harm than good when touching the header (to expand quick // settings), so disable it for this view diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java new file mode 100644 index 000000000000..9730f29da977 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.android.systemui.qs.car; + +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; + +import com.android.systemui.Dependency; +import com.android.systemui.R; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.qs.QSFooter; +import com.android.systemui.qs.QSPanel; +import com.android.systemui.statusbar.phone.MultiUserSwitch; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.UserInfoController; + +/** + * The footer view that displays below the status bar in the auto use-case. This view shows the + * user switcher and access to settings. + */ +public class CarQSFooter extends RelativeLayout implements QSFooter, + UserInfoController.OnUserInfoChangedListener { + private UserInfoController mUserInfoController; + + private MultiUserSwitch mMultiUserSwitch; + private ImageView mMultiUserAvatar; + + public CarQSFooter(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mMultiUserSwitch = findViewById(R.id.multi_user_switch); + mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar); + + mUserInfoController = Dependency.get(UserInfoController.class); + + findViewById(R.id.settings_button).setOnClickListener(v -> { + ActivityStarter activityStarter = Dependency.get(ActivityStarter.class); + + if (!Dependency.get(DeviceProvisionedController.class).isCurrentUserSetup()) { + // If user isn't setup just unlock the device and dump them back at SUW. + activityStarter.postQSRunnableDismissingKeyguard(() -> { }); + return; + } + + activityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS), + true /* dismissShade */); + }); + } + + @Override + public void onUserInfoChanged(String name, Drawable picture, String userAccount) { + mMultiUserAvatar.setImageDrawable(picture); + } + + @Override + public void setQSPanel(@Nullable QSPanel panel) { + if (panel != null) { + mMultiUserSwitch.setQsPanel(panel); + } + } + + @Override + public void setListening(boolean listening) { + if (listening) { + mUserInfoController.addCallback(this); + } else { + mUserInfoController.removeCallback(this); + } + } + + @Nullable + @Override + public View getExpandView() { + // No view that should expand/collapse the quick settings. + return null; + } + + @Override + public void setExpanded(boolean expanded) { + // Do nothing because the quick settings cannot be expanded. + } + + @Override + public void setExpansion(float expansion) { + // Do nothing because the quick settings cannot be expanded. + } + + @Override + public void setKeyguardShowing(boolean keyguardShowing) { + // Do nothing because the footer will not be shown when the keyguard is up. + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java new file mode 100644 index 000000000000..7c2a8129813a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.android.systemui.qs.car; + +import android.app.Fragment; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; + +import com.android.systemui.R; +import com.android.systemui.plugins.qs.QS; +import com.android.systemui.qs.QSFooter; + +/** + * A quick settings fragment for the car. For auto, there is no row for quick settings or ability + * to expand the quick settings panel. Instead, the only thing is that displayed is the + * status bar, and a static row with access to the user switcher and settings. + */ +public class CarQSFragment extends Fragment implements QS { + private View mHeader; + private QSFooter mFooter; + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.car_qs_panel, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mHeader = view.findViewById(R.id.header); + mFooter = view.findViewById(R.id.qs_footer); + } + + @Override + public void hideImmediately() { + getView().setVisibility(View.INVISIBLE); + } + + @Override + public void setQsExpansion(float qsExpansionFraction, float headerTranslation) { + // If the header is to be completed translated down, then set it to be visible. + getView().setVisibility(headerTranslation == 0 ? View.VISIBLE : View.INVISIBLE); + } + + @Override + public View getHeader() { + return mHeader; + } + + @VisibleForTesting + QSFooter getFooter() { + return mFooter; + } + + @Override + public void setHeaderListening(boolean listening) { + mFooter.setListening(listening); + } + + @Override + public void setListening(boolean listening) { + mFooter.setListening(listening); + } + + @Override + public int getQsMinExpansionHeight() { + return getView().getHeight(); + } + + @Override + public int getDesiredHeight() { + return getView().getHeight(); + } + + @Override + public void setPanelView(HeightListener notificationPanelView) { + // No quick settings panel. + } + + @Override + public void setHeightOverride(int desiredHeight) { + // No ability to expand quick settings. + } + + @Override + public void setHeaderClickable(boolean qsExpansionEnabled) { + // Usually this sets the expand button to be clickable, but there is no quick settings to + // expand. + } + + @Override + public boolean isCustomizing() { + // No ability to customize the quick settings. + return false; + } + + @Override + public void setOverscrolling(boolean overscrolling) { + // No overscrolling to reveal quick settings. + } + + @Override + public void setExpanded(boolean qsExpanded) { + // No quick settings to expand + } + + @Override + public boolean isShowingDetail() { + // No detail panel to close. + return false; + } + + @Override + public void closeDetail() { + // No detail panel to close. + } + + @Override + public void setKeyguardShowing(boolean keyguardShowing) { + // No keyguard to show. + } + + @Override + public void animateHeaderSlidingIn(long delay) { + // No header to animate. + } + + @Override + public void animateHeaderSlidingOut() { + // No header to animate. + } + + @Override + public void notifyCustomizeChanged() { + // There is no ability to customize quick settings. + } + + @Override + public void setContainer(ViewGroup container) { + // No quick settings, so no container to set. + } + + @Override + public void setExpandClickListener(OnClickListener onClickListener) { + // No ability to expand the quick settings. + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java new file mode 100644 index 000000000000..6797bb9dbe82 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.android.systemui.qs.car; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.Rect; +import android.support.annotation.IdRes; +import android.util.AttributeSet; +import android.view.View; +import android.widget.RelativeLayout; + +import com.android.settingslib.Utils; +import com.android.systemui.BatteryMeterView; +import com.android.systemui.R; +import com.android.systemui.statusbar.policy.DarkIconDispatcher; + +/** + * A view that forms the header of the notification panel. This view will ensure that any + * status icons that are displayed are tinted accordingly to the current theme. + */ +public class CarStatusBarHeader extends RelativeLayout { + public CarStatusBarHeader(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + // Set the light/dark theming on the header status UI to match the current theme. + int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground); + float intensity = colorForeground == Color.WHITE ? 0f : 1f; + Rect tintArea = new Rect(0, 0, 0, 0); + + applyDarkness(R.id.signal_cluster, tintArea, intensity, colorForeground); + applyDarkness(R.id.battery, tintArea, intensity, colorForeground); + applyDarkness(R.id.clock, tintArea, intensity, colorForeground); + + ((BatteryMeterView) findViewById(R.id.battery)).setForceShowPercent(true); + } + + private void applyDarkness(@IdRes int id, Rect tintArea, float intensity, int color) { + View v = findViewById(id); + if (v instanceof DarkIconDispatcher.DarkReceiver) { + ((DarkIconDispatcher.DarkReceiver) v).onDarkChanged(tintArea, intensity, color); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 4701f85c5ff3..a7731724b807 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -153,7 +153,6 @@ public class NotificationPanelView extends PanelView implements protected int mQsMinExpansionHeight; protected int mQsMaxExpansionHeight; private int mQsPeekHeight; - private boolean mQsOverscrollExpansionEnabled; private boolean mStackScrollerOverscrolling; private boolean mQsExpansionFromOverscroll; private float mLastOverscroll; @@ -242,8 +241,6 @@ public class NotificationPanelView extends PanelView implements super(context, attrs); setWillNotDraw(!DEBUG); mFalsingManager = FalsingManager.getInstance(context); - mQsOverscrollExpansionEnabled = - getResources().getBoolean(R.bool.config_enableQuickSettingsOverscrollExpansion); } public void setStatusBar(StatusBar bar) { @@ -668,7 +665,7 @@ public class NotificationPanelView extends PanelView implements return true; } - if (mQsOverscrollExpansionEnabled && !isFullyCollapsed() && onQsIntercept(event)) { + if (!isFullyCollapsed() && onQsIntercept(event)) { return true; } return super.onInterceptTouchEvent(event); @@ -843,8 +840,7 @@ public class NotificationPanelView extends PanelView implements } handled |= mHeadsUpTouchHelper.onTouchEvent(event); - if (mQsOverscrollExpansionEnabled && !mHeadsUpTouchHelper.isTrackingHeadsUp() - && handleQsTouch(event)) { + if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) { return true; } if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) { @@ -1028,10 +1024,6 @@ public class NotificationPanelView extends PanelView implements @Override public void onOverscrollTopChanged(float amount, boolean isRubberbanded) { - if (!mQsOverscrollExpansionEnabled) { - return; - } - cancelQsAnimation(); if (!mQsExpansionEnabled) { amount = 0f; @@ -1046,10 +1038,6 @@ public class NotificationPanelView extends PanelView implements @Override public void flingTopOverscroll(float velocity, boolean open) { - if (!mQsOverscrollExpansionEnabled) { - return; - } - mLastOverscroll = 0f; mQsExpansionFromOverscroll = false; setQsExpansion(mQsExpansionHeight); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 4d6fd9c136b5..714c287365b3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -182,6 +182,7 @@ import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.Snoo import com.android.systemui.qs.QSFragment; import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QSTileHost; +import com.android.systemui.qs.car.CarQSFragment; import com.android.systemui.recents.Recents; import com.android.systemui.recents.ScreenPinningRequest; import com.android.systemui.recents.events.EventBus; @@ -1149,7 +1150,7 @@ public class StatusBar extends SystemUI implements DemoMode, ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame, Dependency.get(ExtensionController.class).newExtension(QS.class) .withPlugin(QS.class) - .withUiMode(UI_MODE_TYPE_CAR, () -> new QSFragment()) + .withUiMode(UI_MODE_TYPE_CAR, () -> new CarQSFragment()) .withDefault(() -> new QSFragment()) .build()); final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java index c2618cd5edaf..b79137ea68ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java @@ -262,7 +262,8 @@ public class ExtensionControllerImpl implements ExtensionController { public UiModeItem(int uiMode, Supplier<T> supplier) { mDesiredUiMode = uiMode; mSupplier = supplier; - mUiMode = mDefaultContext.getResources().getConfiguration().uiMode; + mUiMode = mDefaultContext.getResources().getConfiguration().uiMode + & Configuration.UI_MODE_TYPE_MASK; Dependency.get(ConfigurationController.class).addCallback(this); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java index d25bbe1e4904..703b4d5e22ec 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java @@ -42,9 +42,9 @@ import org.junit.runner.RunWith; @RunWithLooper @SmallTest @Ignore("failing") -public class QSFooterTest extends LeakCheckedTest { +public class QSFooterImplTest extends LeakCheckedTest { - private QSFooter mFooter; + private QSFooterImpl mFooter; private ActivityStarter mActivityStarter; private DeviceProvisionedController mDeviceProvisionedController; @@ -54,9 +54,9 @@ public class QSFooterTest extends LeakCheckedTest { mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class); mDeviceProvisionedController = mDependency.injectMockDependency( DeviceProvisionedController.class); - TestableLooper.get(this).runWithLooper(() -> { - mFooter = (QSFooter) LayoutInflater.from(mContext).inflate(R.layout.qs_footer, null); - }); + TestableLooper.get(this).runWithLooper( + () -> mFooter = (QSFooterImpl) LayoutInflater.from(mContext).inflate( + R.layout.qs_footer_impl, null)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java new file mode 100644 index 000000000000..4f87b02ed35f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.android.systemui.qs.car; + +import static org.junit.Assert.assertNotNull; + +import android.content.Context; +import android.support.test.filters.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.LayoutInflaterBuilder; +import android.testing.TestableLooper; +import android.testing.TestableLooper.RunWithLooper; +import android.view.View; +import android.widget.FrameLayout; + +import com.android.keyguard.CarrierText; +import com.android.systemui.Dependency; +import com.android.systemui.SysuiBaseFragmentTest; +import com.android.systemui.statusbar.policy.Clock; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests for {@link CarQSFragment}. + */ +@RunWith(AndroidTestingRunner.class) +@RunWithLooper(setAsMainLooper = true) +@SmallTest +public class CarQsFragmentTest extends SysuiBaseFragmentTest { + public CarQsFragmentTest() { + super(CarQSFragment.class); + } + + @Before + public void initDependencies() { + mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, + new LayoutInflaterBuilder(mContext) + .replace("com.android.systemui.statusbar.policy.SplitClockView", + FrameLayout.class) + .replace("TextClock", View.class) + .replace(CarrierText.class, View.class) + .replace(Clock.class, View.class) + .build()); + + mDependency.injectTestDependency(Dependency.BG_LOOPER, + TestableLooper.get(this).getLooper()); + } + + @Test + public void testLayoutInflation() { + CarQSFragment fragment = (CarQSFragment) mFragment; + mFragments.dispatchResume(); + + assertNotNull(fragment.getHeader()); + assertNotNull(fragment.getFooter()); + } + + @Test + public void testListening() { + CarQSFragment qs = (CarQSFragment) mFragment; + mFragments.dispatchResume(); + processAllMessages(); + + qs.setListening(true); + processAllMessages(); + + qs.setListening(false); + processAllMessages(); + } +} |