1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.qs.tiles;
18 
19 import android.content.Intent;
20 import android.os.Handler;
21 import android.os.Looper;
22 import android.service.quicksettings.Tile;
23 import android.util.Log;
24 import android.view.View;
25 
26 import androidx.annotation.Nullable;
27 
28 import com.android.internal.jank.InteractionJankMonitor;
29 import com.android.internal.logging.MetricsLogger;
30 import com.android.systemui.R;
31 import com.android.systemui.animation.ActivityLaunchAnimator;
32 import com.android.systemui.dagger.qualifiers.Background;
33 import com.android.systemui.dagger.qualifiers.Main;
34 import com.android.systemui.plugins.ActivityStarter;
35 import com.android.systemui.plugins.FalsingManager;
36 import com.android.systemui.plugins.qs.QSTile;
37 import com.android.systemui.plugins.statusbar.StatusBarStateController;
38 import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
39 import com.android.systemui.qs.QSHost;
40 import com.android.systemui.qs.QsEventLogger;
41 import com.android.systemui.qs.logging.QSLogger;
42 import com.android.systemui.qs.tileimpl.QSTileImpl;
43 
44 import javax.inject.Inject;
45 
46 /** Quick settings tile: QR Code Scanner **/
47 public class QRCodeScannerTile extends QSTileImpl<QSTile.State> {
48 
49     public static final String TILE_SPEC = "qr_code_scanner";
50 
51     private static final String TAG = "QRCodeScanner";
52 
53     private final CharSequence mLabel = mContext.getString(R.string.qr_code_scanner_title);
54     private final QRCodeScannerController mQRCodeScannerController;
55 
56     private final QRCodeScannerController.Callback mCallback =
57             new QRCodeScannerController.Callback() {
58                 public void onQRCodeScannerActivityChanged() {
59                     refreshState();
60                 }
61             };
62 
63     @Inject
QRCodeScannerTile( QSHost host, QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, QRCodeScannerController qrCodeScannerController)64     public QRCodeScannerTile(
65             QSHost host,
66             QsEventLogger uiEventLogger,
67             @Background Looper backgroundLooper,
68             @Main Handler mainHandler,
69             FalsingManager falsingManager,
70             MetricsLogger metricsLogger,
71             StatusBarStateController statusBarStateController,
72             ActivityStarter activityStarter,
73             QSLogger qsLogger,
74             QRCodeScannerController qrCodeScannerController) {
75         super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
76                 statusBarStateController, activityStarter, qsLogger);
77         mQRCodeScannerController = qrCodeScannerController;
78         mQRCodeScannerController.observe(getLifecycle(), mCallback);
79     }
80 
81     @Override
handleInitialize()82     protected void handleInitialize() {
83         mQRCodeScannerController.registerQRCodeScannerChangeObservers(
84                 QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE);
85     }
86 
87     @Override
handleDestroy()88     protected void handleDestroy() {
89         super.handleDestroy();
90         mQRCodeScannerController.unregisterQRCodeScannerChangeObservers(
91                 QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE);
92     }
93 
94     @Override
newTileState()95     public State newTileState() {
96         State state = new State();
97         state.handlesLongClick = false;
98         return state;
99     }
100 
101     @Override
handleClick(@ullable View view)102     protected void handleClick(@Nullable View view) {
103         Intent intent = mQRCodeScannerController.getIntent();
104         if (intent == null) {
105             // This should never happen as the fact that we are handling clicks means that the
106             // scanner is available. This is just a safety check.
107             Log.e(TAG, "Expected a non-null intent");
108             return;
109         }
110 
111         ActivityLaunchAnimator.Controller animationController =
112                 view == null ? null : ActivityLaunchAnimator.Controller.fromView(view,
113                         InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE);
114         mActivityStarter.startActivity(intent, true /* dismissShade */,
115                 animationController, true /* showOverLockscreenWhenLocked */);
116     }
117 
118     @Override
handleUpdateState(State state, Object arg)119     protected void handleUpdateState(State state, Object arg) {
120         state.label = mContext.getString(R.string.qr_code_scanner_title);
121         state.contentDescription = state.label;
122         state.icon = ResourceIcon.get(R.drawable.ic_qr_code_scanner);
123         state.state = mQRCodeScannerController.isAbleToLaunchScannerActivity() ? Tile.STATE_INACTIVE
124                 : Tile.STATE_UNAVAILABLE;
125         // The assumption is that if the OEM has the QR code scanner module enabled then the scanner
126         // would go to "Unavailable" state only when GMS core is updating.
127         state.secondaryLabel = state.state == Tile.STATE_UNAVAILABLE
128                 ? mContext.getString(R.string.qr_code_scanner_updating_secondary_label) : null;
129     }
130 
131     @Override
getMetricsCategory()132     public int getMetricsCategory() {
133         // New logging doesn't use this, keeping the function for legacy code.
134         return 0;
135     }
136 
137     @Override
isAvailable()138     public boolean isAvailable() {
139         return mQRCodeScannerController.isCameraAvailable();
140     }
141 
142     @Nullable
143     @Override
getLongClickIntent()144     public Intent getLongClickIntent() {
145         return null;
146     }
147 
148     @Override
getTileLabel()149     public CharSequence getTileLabel() {
150         return mLabel;
151     }
152 }
153