1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package com.android.systemui.qs.tiles;
16 
17 import android.content.Intent;
18 import android.os.Handler;
19 import android.os.Looper;
20 import android.provider.Settings;
21 import android.service.quicksettings.Tile;
22 import android.view.View;
23 import android.widget.Switch;
24 
25 import androidx.annotation.Nullable;
26 
27 import com.android.internal.jank.InteractionJankMonitor;
28 import com.android.internal.logging.MetricsLogger;
29 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
30 import com.android.systemui.Prefs;
31 import com.android.systemui.R;
32 import com.android.systemui.animation.DialogCuj;
33 import com.android.systemui.animation.DialogLaunchAnimator;
34 import com.android.systemui.dagger.qualifiers.Background;
35 import com.android.systemui.dagger.qualifiers.Main;
36 import com.android.systemui.plugins.ActivityStarter;
37 import com.android.systemui.plugins.FalsingManager;
38 import com.android.systemui.plugins.qs.QSTile.BooleanState;
39 import com.android.systemui.plugins.statusbar.StatusBarStateController;
40 import com.android.systemui.qs.QSHost;
41 import com.android.systemui.qs.QsEventLogger;
42 import com.android.systemui.qs.logging.QSLogger;
43 import com.android.systemui.qs.tileimpl.QSTileImpl;
44 import com.android.systemui.statusbar.phone.SystemUIDialog;
45 import com.android.systemui.statusbar.policy.DataSaverController;
46 
47 import javax.inject.Inject;
48 
49 public class DataSaverTile extends QSTileImpl<BooleanState> implements
50         DataSaverController.Listener{
51 
52     public static final String TILE_SPEC = "saver";
53 
54     private static final String INTERACTION_JANK_TAG = "start_data_saver";
55 
56     private final DataSaverController mDataSaverController;
57     private final DialogLaunchAnimator mDialogLaunchAnimator;
58 
59     @Inject
DataSaverTile( QSHost host, QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, DataSaverController dataSaverController, DialogLaunchAnimator dialogLaunchAnimator )60     public DataSaverTile(
61             QSHost host,
62             QsEventLogger uiEventLogger,
63             @Background Looper backgroundLooper,
64             @Main Handler mainHandler,
65             FalsingManager falsingManager,
66             MetricsLogger metricsLogger,
67             StatusBarStateController statusBarStateController,
68             ActivityStarter activityStarter,
69             QSLogger qsLogger,
70             DataSaverController dataSaverController,
71             DialogLaunchAnimator dialogLaunchAnimator
72     ) {
73         super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
74                 statusBarStateController, activityStarter, qsLogger);
75         mDataSaverController = dataSaverController;
76         mDialogLaunchAnimator = dialogLaunchAnimator;
77         mDataSaverController.observe(getLifecycle(), this);
78     }
79 
80     @Override
newTileState()81     public BooleanState newTileState() {
82         return new BooleanState();
83     }
84 
85     @Override
getLongClickIntent()86     public Intent getLongClickIntent() {
87         return new Intent(Settings.ACTION_DATA_SAVER_SETTINGS);
88     }
89     @Override
handleClick(@ullable View view)90     protected void handleClick(@Nullable View view) {
91         if (mState.value
92                 || Prefs.getBoolean(mContext, Prefs.Key.QS_DATA_SAVER_DIALOG_SHOWN, false)) {
93             // Do it right away.
94             toggleDataSaver();
95             return;
96         }
97 
98         // Show a dialog to confirm first. Dialogs shown by the DialogLaunchAnimator must be created
99         // and shown on the main thread, so we post it to the UI handler.
100         mUiHandler.post(() -> {
101             SystemUIDialog dialog = new SystemUIDialog(mContext);
102             dialog.setTitle(com.android.internal.R.string.data_saver_enable_title);
103             dialog.setMessage(com.android.internal.R.string.data_saver_description);
104             dialog.setPositiveButton(com.android.internal.R.string.data_saver_enable_button,
105                     (dialogInterface, which) -> {
106                         toggleDataSaver();
107                         Prefs.putBoolean(mContext, Prefs.Key.QS_DATA_SAVER_DIALOG_SHOWN, true);
108                     });
109             dialog.setNeutralButton(com.android.internal.R.string.cancel, null);
110             dialog.setShowForAllUsers(true);
111 
112             if (view != null) {
113                 mDialogLaunchAnimator.showFromView(dialog, view, new DialogCuj(
114                         InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
115                         INTERACTION_JANK_TAG));
116             } else {
117                 dialog.show();
118             }
119         });
120     }
121 
toggleDataSaver()122     private void toggleDataSaver() {
123         mState.value = !mDataSaverController.isDataSaverEnabled();
124         mDataSaverController.setDataSaverEnabled(mState.value);
125         refreshState(mState.value);
126     }
127 
128     @Override
getTileLabel()129     public CharSequence getTileLabel() {
130         return mContext.getString(R.string.data_saver);
131     }
132 
133     @Override
handleUpdateState(BooleanState state, Object arg)134     protected void handleUpdateState(BooleanState state, Object arg) {
135         state.value = arg instanceof Boolean ? ((Boolean) arg).booleanValue()
136                 : mDataSaverController.isDataSaverEnabled();
137         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
138         state.label = mContext.getString(R.string.data_saver);
139         state.contentDescription = state.label;
140         state.icon = ResourceIcon.get(state.value ? R.drawable.qs_data_saver_icon_on
141                 : R.drawable.qs_data_saver_icon_off);
142         state.expandedAccessibilityClassName = Switch.class.getName();
143     }
144 
145     @Override
getMetricsCategory()146     public int getMetricsCategory() {
147         return MetricsEvent.QS_DATA_SAVER;
148     }
149 
150     @Override
onDataSaverChanged(boolean isDataSaving)151     public void onDataSaverChanged(boolean isDataSaving) {
152         refreshState(isDataSaving);
153     }
154 }
155