• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.car.qc;
18 
19 import static android.car.Car.CarServiceLifecycleListener;
20 
21 import static com.android.systemui.car.users.CarSystemUIUserUtil.getCurrentUserHandle;
22 
23 import android.app.ActivityOptions;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.res.TypedArray;
27 import android.util.AttributeSet;
28 import android.util.Log;
29 import android.view.View;
30 
31 import androidx.annotation.Nullable;
32 import androidx.annotation.VisibleForTesting;
33 import androidx.constraintlayout.widget.ConstraintLayout;
34 
35 import com.android.car.ui.utils.CarUxRestrictionsUtil;
36 import com.android.systemui.R;
37 import com.android.systemui.broadcast.BroadcastDispatcher;
38 import com.android.systemui.settings.UserTracker;
39 
40 import java.net.URISyntaxException;
41 
42 /**
43  * Footer button layout which contains one or multiple views for quick control panels.
44  *
45  * Allows for an intent action to be specified via the
46  * {@link R.styleable.QCFooterButtonView_intent} attribute and for enabled state to be set
47  * according to driving mode via the {@link R.styleable.QCFooterButtonView_disableWhileDriving}
48  * attribute.
49  */
50 public class QCFooterButtonView extends ConstraintLayout {
51     private static final String TAG = QCFooterButtonView.class.getSimpleName();
52 
53     private boolean mDisableWhileDriving;
54     private final CarUxRestrictionsUtil.OnUxRestrictionsChangedListener mListener =
55             carUxRestrictions -> setEnabled(!carUxRestrictions.isRequiresDistractionOptimization());
56     @Nullable
57     protected UserTracker mUserTracker;
58 
59     @Nullable
60     protected BroadcastDispatcher mBroadcastDispatcher;
61 
62     @Nullable
63     View.OnClickListener mOnClickListener;
64 
65     @Nullable
66     CarServiceLifecycleListener mCarServiceLifecycleListener;
67 
QCFooterButtonView(Context context)68     public QCFooterButtonView(Context context) {
69         this(context, null);
70     }
71 
QCFooterButtonView(Context context, AttributeSet attrs)72     public QCFooterButtonView(Context context, AttributeSet attrs) {
73         this(context, attrs, 0);
74     }
75 
QCFooterButtonView(Context context, AttributeSet attrs, int defStyleAttr)76     public QCFooterButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
77         this(context, attrs, defStyleAttr, 0);
78     }
79 
QCFooterButtonView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)80     public QCFooterButtonView(Context context, AttributeSet attrs, int defStyleAttr,
81             int defStyleRes) {
82         super(context, attrs, defStyleAttr, defStyleRes);
83         if (attrs == null) {
84             return;
85         }
86 
87         TypedArray typedArray = context.obtainStyledAttributes(attrs,
88                 R.styleable.QCFooterButtonView);
89         String intentString = typedArray.getString(R.styleable.QCFooterButtonView_intent);
90         if (intentString != null) {
91             Intent intent;
92             try {
93                 intent = Intent.parseUri(intentString, Intent.URI_INTENT_SCHEME);
94             } catch (URISyntaxException e) {
95                 throw new RuntimeException("Failed to attach intent", e);
96             }
97             Intent finalIntent = intent;
98 
99             mOnClickListener = v -> {
100                 mContext.sendBroadcastAsUser(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS),
101                         getCurrentUserHandle(mContext, mUserTracker));
102                 try {
103                     ActivityOptions options = ActivityOptions.makeBasic();
104                     options.setLaunchDisplayId(mContext.getDisplayId());
105                     mContext.startActivityAsUser(finalIntent, options.toBundle(),
106                             getCurrentUserHandle(mContext, mUserTracker));
107                 } catch (Exception e) {
108                     Log.e(TAG, "Failed to launch intent", e);
109                 }
110             };
111             setOnClickListener(mOnClickListener);
112         }
113 
114         mDisableWhileDriving = typedArray.getBoolean(
115                 R.styleable.QCFooterButtonView_disableWhileDriving, /* defValue= */ false);
116 
117         typedArray.recycle();
118     }
119 
setUserTracker(UserTracker userTracker)120     public void setUserTracker(UserTracker userTracker) {
121         mUserTracker = userTracker;
122     }
123 
setBroadcastDispatcher(BroadcastDispatcher broadcastDispatcher)124     public void setBroadcastDispatcher(BroadcastDispatcher broadcastDispatcher) {
125         mBroadcastDispatcher = broadcastDispatcher;
126     }
127 
128     @Override
onAttachedToWindow()129     protected void onAttachedToWindow() {
130         super.onAttachedToWindow();
131         if (mDisableWhileDriving) {
132             CarUxRestrictionsUtil.getInstance(mContext).register(mListener);
133         }
134     }
135 
136     @Override
onDetachedFromWindow()137     protected void onDetachedFromWindow() {
138         super.onDetachedFromWindow();
139         if (mDisableWhileDriving) {
140             CarUxRestrictionsUtil.getInstance(mContext).unregister(mListener);
141         }
142     }
143 
144     @Nullable
145     @VisibleForTesting
getOnClickListener()146     protected View.OnClickListener getOnClickListener() {
147         return mOnClickListener;
148     }
149 
150     @Nullable
151     @VisibleForTesting
getCarServiceLifecycleListener()152     protected CarServiceLifecycleListener getCarServiceLifecycleListener() {
153         return mCarServiceLifecycleListener;
154     }
155 }
156