blob: faeda2c2bee4a611f9cfad01010e23d31b599e6a [file] [log] [blame]
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +08001/*
2 * Copyright 2018 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
17package com.google.android.setupcompat;
18
19import android.annotation.TargetApi;
20import android.app.Activity;
21import android.content.Context;
22import android.content.ContextWrapper;
23import android.content.res.TypedArray;
Setup Wizard Team1ed30732019-03-14 10:00:10 +080024import android.os.Build.VERSION;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080025import android.os.Build.VERSION_CODES;
Setup Wizard Team1d79d002018-12-13 14:30:13 +080026import android.os.PersistableBundle;
Setup Wizard Team1ed30732019-03-14 10:00:10 +080027import androidx.annotation.ColorInt;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080028import androidx.annotation.LayoutRes;
29import android.util.AttributeSet;
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +080030import android.util.Log;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080031import android.view.LayoutInflater;
32import android.view.View;
33import android.view.ViewGroup;
34import android.view.ViewStub;
35import android.view.WindowManager;
Setup Wizard Teamd6fc4af2019-12-31 20:58:11 +080036import com.google.android.setupcompat.internal.PersistableBundles;
Maurice Lamc4529322019-02-14 22:04:56 +000037import com.google.android.setupcompat.internal.TemplateLayout;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080038import com.google.android.setupcompat.lifecycle.LifecycleFragment;
Setup Wizard Team1d79d002018-12-13 14:30:13 +080039import com.google.android.setupcompat.logging.CustomEvent;
40import com.google.android.setupcompat.logging.MetricKey;
41import com.google.android.setupcompat.logging.SetupMetricsLogger;
Setup Wizard Team1ed30732019-03-14 10:00:10 +080042import com.google.android.setupcompat.partnerconfig.PartnerConfig;
43import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper;
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +080044import com.google.android.setupcompat.template.FooterBarMixin;
45import com.google.android.setupcompat.template.FooterButton;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080046import com.google.android.setupcompat.template.StatusBarMixin;
47import com.google.android.setupcompat.template.SystemNavBarMixin;
48import com.google.android.setupcompat.util.WizardManagerHelper;
49
50/** A templatization layout with consistent style used in Setup Wizard or app itself. */
51public class PartnerCustomizationLayout extends TemplateLayout {
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +080052 // Log tags can have at most 23 characters on N or before.
53 private static final String TAG = "PartnerCustomizedLayout";
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080054
Setup Wizard Team1ed30732019-03-14 10:00:10 +080055 private final boolean suwVersionSupportPartnerResource = isAtLeastQ();
56
57 private boolean applyPartnerResource;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080058 private Activity activity;
59
60 public PartnerCustomizationLayout(Context context) {
61 this(context, 0, 0);
62 }
63
64 public PartnerCustomizationLayout(Context context, int template) {
65 this(context, template, 0);
66 }
67
68 public PartnerCustomizationLayout(Context context, int template, int containerId) {
69 super(context, template, containerId);
70 init(null, R.attr.sucLayoutTheme);
71 }
72
73 public PartnerCustomizationLayout(Context context, AttributeSet attrs) {
74 super(context, attrs);
75 init(attrs, R.attr.sucLayoutTheme);
76 }
77
78 @TargetApi(VERSION_CODES.HONEYCOMB)
79 public PartnerCustomizationLayout(Context context, AttributeSet attrs, int defStyleAttr) {
80 super(context, attrs, defStyleAttr);
81 init(attrs, defStyleAttr);
82 }
83
84 private void init(AttributeSet attrs, int defStyleAttr) {
85 activity = lookupActivityFromContext(getContext());
86
87 boolean isSetupFlow = WizardManagerHelper.isAnySetupWizard(activity.getIntent());
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080088
89 TypedArray a =
90 getContext()
91 .obtainStyledAttributes(
92 attrs, R.styleable.SucPartnerCustomizationLayout, defStyleAttr, 0);
93
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080094 boolean layoutFullscreen =
95 a.getBoolean(R.styleable.SucPartnerCustomizationLayout_sucLayoutFullscreen, true);
Setup Wizard Teamff4fecb2018-12-19 11:31:37 +080096
97 boolean usePartnerResource =
98 a.getBoolean(R.styleable.SucPartnerCustomizationLayout_sucUsePartnerResource, true);
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080099 a.recycle();
100
Setup Wizard Team1ed30732019-03-14 10:00:10 +0800101 if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && layoutFullscreen) {
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800102 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
103 }
104
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800105 Log.i(
106 TAG,
Maurice Lamc4529322019-02-14 22:04:56 +0000107 "activity="
108 + activity.getClass().getSimpleName()
109 + ", isSetupFlow="
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800110 + isSetupFlow
111 + ", applyPartnerResource="
112 + applyPartnerResource()
113 + ", usePartnerResource="
114 + usePartnerResource);
115
116 if (suwVersionSupportPartnerResource && isSetupFlow && !applyPartnerResource()) {
Setup Wizard Team1ed30732019-03-14 10:00:10 +0800117 Log.w(TAG, "applyPartnerResource() should return true during setup wizard flow");
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800118 }
119
Setup Wizard Team1ed30732019-03-14 10:00:10 +0800120 applyPartnerResource =
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800121 suwVersionSupportPartnerResource
122 && applyPartnerResource()
123 && (isSetupFlow || usePartnerResource);
Setup Wizard Teamff4fecb2018-12-19 11:31:37 +0800124 registerMixin(
125 StatusBarMixin.class,
126 new StatusBarMixin(this, activity.getWindow(), attrs, defStyleAttr, applyPartnerResource));
127 registerMixin(
128 SystemNavBarMixin.class,
Setup Wizard Team1ed30732019-03-14 10:00:10 +0800129 new SystemNavBarMixin(this, activity.getWindow(), applyPartnerResource));
Setup Wizard Teamff4fecb2018-12-19 11:31:37 +0800130 registerMixin(
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800131 FooterBarMixin.class, new FooterBarMixin(this, attrs, defStyleAttr, applyPartnerResource));
Setup Wizard Teamff4fecb2018-12-19 11:31:37 +0800132
Setup Wizard Team1ed30732019-03-14 10:00:10 +0800133 getMixin(SystemNavBarMixin.class).applyPartnerCustomizations(attrs, defStyleAttr);
134
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800135 // Override the FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_TRANSLUCENT_STATUS,
136 // FLAG_TRANSLUCENT_NAVIGATION and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN attributes of window forces
137 // showing status bar and navigation bar.
138 activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
139 activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
140 activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
Setup Wizard Team1ed30732019-03-14 10:00:10 +0800141
142 if (applyPartnerResource) {
143 updateContentBackgroundColorWithPartnerConfig();
144 }
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800145 }
146
147 @Override
148 protected View onInflateTemplate(LayoutInflater inflater, int template) {
149 if (template == 0) {
150 template = R.layout.partner_customization_layout;
151 }
152 return inflateTemplate(inflater, 0, template);
153 }
154
155 @Override
156 protected ViewGroup findContainer(int containerId) {
157 if (containerId == 0) {
158 containerId = R.id.suc_layout_content;
159 }
160 return super.findContainer(containerId);
161 }
162
163 @Override
164 protected void onAttachedToWindow() {
165 super.onAttachedToWindow();
Setup Wizard Team1d79d002018-12-13 14:30:13 +0800166 LifecycleFragment.attachNow(activity);
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800167 getMixin(FooterBarMixin.class).onAttachedToWindow();
Setup Wizard Team1d79d002018-12-13 14:30:13 +0800168 }
169
170 @Override
171 protected void onDetachedFromWindow() {
172 super.onDetachedFromWindow();
Maurice Lamc4529322019-02-14 22:04:56 +0000173 if (suwVersionSupportPartnerResource
174 && WizardManagerHelper.isAnySetupWizard(activity.getIntent())) {
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800175 FooterBarMixin footerBarMixin = getMixin(FooterBarMixin.class);
176 footerBarMixin.onDetachedFromWindow();
177 FooterButton primaryButton = footerBarMixin.getPrimaryButton();
178 FooterButton secondaryButton = footerBarMixin.getSecondaryButton();
179 PersistableBundle primaryButtonMetrics =
180 primaryButton != null
181 ? primaryButton.getMetrics("PrimaryFooterButton")
182 : PersistableBundle.EMPTY;
183 PersistableBundle secondaryButtonMetrics =
184 secondaryButton != null
185 ? secondaryButton.getMetrics("SecondaryFooterButton")
186 : PersistableBundle.EMPTY;
187
Setup Wizard Teamd6fc4af2019-12-31 20:58:11 +0800188 PersistableBundle persistableBundle =
189 PersistableBundles.mergeBundles(
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800190 footerBarMixin.getLoggingMetrics(), primaryButtonMetrics, secondaryButtonMetrics);
191
Setup Wizard Team1d79d002018-12-13 14:30:13 +0800192 SetupMetricsLogger.logCustomEvent(
193 getContext(),
194 CustomEvent.create(
195 MetricKey.get("SetupCompatMetrics", activity.getClass().getSimpleName()),
196 persistableBundle));
197 }
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800198 }
199
200 private static Activity lookupActivityFromContext(Context context) {
201 if (context instanceof Activity) {
202 return (Activity) context;
203 } else if (context instanceof ContextWrapper) {
204 return lookupActivityFromContext(((ContextWrapper) context).getBaseContext());
205 } else {
206 throw new IllegalArgumentException("Cannot find instance of Activity in parent tree");
207 }
208 }
209
Setup Wizard Team1ed30732019-03-14 10:00:10 +0800210 // TODO(b/127925696): remove the code for pre-release version of Android Q
211 private static boolean isAtLeastQ() {
212 return (VERSION.SDK_INT > VERSION_CODES.P)
213 || (VERSION.CODENAME.length() == 1
214 && VERSION.CODENAME.charAt(0) >= 'Q'
215 && VERSION.CODENAME.charAt(0) <= 'Z');
216 }
217
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800218 /**
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800219 * This method determines applying the partner resource regardless inside setup wizard flow or
220 * not. It always returns true indicating applying partner resource inside setup wizard flow and
221 * applying customized attributes outside setup wizard flow. Subclasses can override this method
222 * to change applying flow. If Returns false, the layout forces applying customized attributes.
223 */
224 protected boolean applyPartnerResource() {
225 return true;
226 }
227
228 /**
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800229 * Sets the footer of the layout, which is at the bottom of the content area outside the scrolling
230 * container. The footer can only be inflated once per instance of this layout.
231 *
232 * @param footer The layout to be inflated as footer.
233 * @return The root of the inflated footer view.
234 */
235 public View inflateFooter(@LayoutRes int footer) {
236 ViewStub footerStub = findManagedViewById(R.id.suc_layout_footer);
237 footerStub.setLayoutResource(footer);
238 return footerStub.inflate();
239 }
Setup Wizard Team1ed30732019-03-14 10:00:10 +0800240
241 /** Returns if the current layout/activity applies partner customized configurations or not. */
242 protected boolean shouldApplyPartnerResource() {
243 return applyPartnerResource;
244 }
245
246 /** Updates the background color of this layout with the partner-customizable background color. */
247 private void updateContentBackgroundColorWithPartnerConfig() {
248 @ColorInt
249 int color =
250 PartnerConfigHelper.get(getContext())
251 .getColor(getContext(), PartnerConfig.CONFIG_LAYOUT_BACKGROUND_COLOR);
252 this.getRootView().setBackgroundColor(color);
253 }
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800254}