blob: 6a4f73278f131962a2d66a6b83c23d442e1c17dc [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
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080019import android.app.Activity;
20import android.content.Context;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080021import android.content.res.TypedArray;
Setup Wizard Teamde9b52a2019-04-01 10:27:47 +080022import android.os.Build;
Setup Wizard Team1ed30732019-03-14 10:00:10 +080023import android.os.Build.VERSION;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080024import android.os.Build.VERSION_CODES;
Setup Wizard Team1d79d002018-12-13 14:30:13 +080025import android.os.PersistableBundle;
Pasty Changf425dc32025-03-02 22:16:51 -080026import androidx.fragment.app.Fragment;
27import androidx.fragment.app.FragmentActivity;
28import androidx.fragment.app.FragmentManager;
29import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080030import android.util.AttributeSet;
31import android.view.LayoutInflater;
32import android.view.View;
33import android.view.ViewGroup;
Setup Wizard Team55addcd2022-01-06 23:50:39 +080034import android.view.ViewTreeObserver;
Pasty Changf3ba27a2025-02-23 23:52:07 -080035import android.view.WindowInsets;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080036import android.view.WindowManager;
Pasty Changf3ba27a2025-02-23 23:52:07 -080037import android.widget.LinearLayout;
Setup Wizard Team55addcd2022-01-06 23:50:39 +080038import androidx.annotation.VisibleForTesting;
39import com.google.android.setupcompat.internal.FocusChangedMetricHelper;
Setup Wizard Teamde9b52a2019-04-01 10:27:47 +080040import com.google.android.setupcompat.internal.LifecycleFragment;
Setup Wizard Teamd6fc4af2019-12-31 20:58:11 +080041import com.google.android.setupcompat.internal.PersistableBundles;
Setup Wizard Team55addcd2022-01-06 23:50:39 +080042import com.google.android.setupcompat.internal.SetupCompatServiceInvoker;
Maurice Lamc4529322019-02-14 22:04:56 +000043import com.google.android.setupcompat.internal.TemplateLayout;
Setup Wizard Team1d79d002018-12-13 14:30:13 +080044import com.google.android.setupcompat.logging.CustomEvent;
Setup Wizard Team4f5bbf42023-12-20 03:05:46 +000045import com.google.android.setupcompat.logging.LoggingObserver;
46import com.google.android.setupcompat.logging.LoggingObserver.SetupCompatUiEvent.LayoutInflatedEvent;
Setup Wizard Team1d79d002018-12-13 14:30:13 +080047import com.google.android.setupcompat.logging.MetricKey;
48import com.google.android.setupcompat.logging.SetupMetricsLogger;
Pasty Changf3ba27a2025-02-23 23:52:07 -080049import com.google.android.setupcompat.partnerconfig.PartnerConfig;
Setup Wizard Team1ed30732019-03-14 10:00:10 +080050import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper;
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +080051import com.google.android.setupcompat.template.FooterBarMixin;
52import com.google.android.setupcompat.template.FooterButton;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080053import com.google.android.setupcompat.template.StatusBarMixin;
54import com.google.android.setupcompat.template.SystemNavBarMixin;
Setup Wizard Team8a37aa82021-04-26 10:01:19 +080055import com.google.android.setupcompat.util.BuildCompatUtils;
Setup Wizard Teamf513dd22021-06-10 15:49:36 +080056import com.google.android.setupcompat.util.Logger;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080057import com.google.android.setupcompat.util.WizardManagerHelper;
Setup Wizard Team0d3126a2022-04-27 09:03:55 +080058import com.google.errorprone.annotations.CanIgnoreReturnValue;
Pasty Changf425dc32025-03-02 22:16:51 -080059import org.jspecify.annotations.NonNull;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080060
61/** A templatization layout with consistent style used in Setup Wizard or app itself. */
62public class PartnerCustomizationLayout extends TemplateLayout {
Setup Wizard Teamf513dd22021-06-10 15:49:36 +080063
64 private static final Logger LOG = new Logger("PartnerCustomizationLayout");
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080065
Setup Wizard Team67e7fef2019-03-23 08:06:48 +080066 /**
67 * Attribute indicating whether usage of partner theme resources is allowed. This corresponds to
68 * the {@code app:sucUsePartnerResource} XML attribute. Note that when running in setup wizard,
69 * this is always overridden to true.
70 */
Setup Wizard Teamde9b52a2019-04-01 10:27:47 +080071 private boolean usePartnerResourceAttr;
Setup Wizard Team1ed30732019-03-14 10:00:10 +080072
Setup Wizard Team8a37aa82021-04-26 10:01:19 +080073 /**
74 * Attribute indicating whether using full dynamic colors or not. This corresponds to the {@code
75 * app:sucFullDynamicColor} XML attribute.
76 */
77 private boolean useFullDynamicColorAttr;
78
79 /**
80 * Attribute indicating whether usage of dynamic is allowed. This corresponds to the existence of
81 * {@code app:sucFullDynamicColor} XML attribute.
82 */
83 private boolean useDynamicColor;
84
Pasty Changc2366eb2025-01-14 18:11:56 -080085 protected Activity activity;
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080086
David Liu534db6a2023-02-15 06:55:44 +000087 private PersistableBundle layoutTypeBundle;
88
Pasty Changf425dc32025-03-02 22:16:51 -080089 @VisibleForTesting FragmentLifecycleCallbacks fragmentLifecycleCallbacks;
90
Pasty Changf3ba27a2025-02-23 23:52:07 -080091 private int footerBarPaddingBottom;
92
Setup Wizard Team0d3126a2022-04-27 09:03:55 +080093 @CanIgnoreReturnValue
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080094 public PartnerCustomizationLayout(Context context) {
95 this(context, 0, 0);
96 }
97
Setup Wizard Team0d3126a2022-04-27 09:03:55 +080098 @CanIgnoreReturnValue
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +080099 public PartnerCustomizationLayout(Context context, int template) {
100 this(context, template, 0);
101 }
102
Setup Wizard Team0d3126a2022-04-27 09:03:55 +0800103 @CanIgnoreReturnValue
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800104 public PartnerCustomizationLayout(Context context, int template, int containerId) {
105 super(context, template, containerId);
106 init(null, R.attr.sucLayoutTheme);
107 }
108
Setup Wizard Team0d3126a2022-04-27 09:03:55 +0800109 @CanIgnoreReturnValue
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800110 public PartnerCustomizationLayout(Context context, AttributeSet attrs) {
111 super(context, attrs);
112 init(attrs, R.attr.sucLayoutTheme);
113 }
114
Setup Wizard Team0d3126a2022-04-27 09:03:55 +0800115 @CanIgnoreReturnValue
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800116 public PartnerCustomizationLayout(Context context, AttributeSet attrs, int defStyleAttr) {
117 super(context, attrs, defStyleAttr);
118 init(attrs, defStyleAttr);
119 }
120
David Liu534db6a2023-02-15 06:55:44 +0000121 @VisibleForTesting
122 final ViewTreeObserver.OnWindowFocusChangeListener windowFocusChangeListener =
123 this::onFocusChanged;
124
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800125 private void init(AttributeSet attrs, int defStyleAttr) {
Setup Wizard Team261f8b42021-03-04 09:18:37 +0800126 if (isInEditMode()) {
127 return;
128 }
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800129
130 TypedArray a =
131 getContext()
132 .obtainStyledAttributes(
133 attrs, R.styleable.SucPartnerCustomizationLayout, defStyleAttr, 0);
134
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800135 boolean layoutFullscreen =
136 a.getBoolean(R.styleable.SucPartnerCustomizationLayout_sucLayoutFullscreen, true);
Setup Wizard Teamff4fecb2018-12-19 11:31:37 +0800137
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800138 a.recycle();
139
Pasty Changf3ba27a2025-02-23 23:52:07 -0800140 // Get the footer bar default padding bottom value.
141 TypedArray footerBarMixinAttrs =
142 getContext().obtainStyledAttributes(attrs, R.styleable.SucFooterBarMixin, defStyleAttr, 0);
143 int defaultPadding =
144 footerBarMixinAttrs.getDimensionPixelSize(
145 R.styleable.SucFooterBarMixin_sucFooterBarPaddingVertical, 0);
146 footerBarPaddingBottom =
147 footerBarMixinAttrs.getDimensionPixelSize(
148 R.styleable.SucFooterBarMixin_sucFooterBarPaddingBottom, defaultPadding);
149
150 footerBarMixinAttrs.recycle();
151
Setup Wizard Team1ed30732019-03-14 10:00:10 +0800152 if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && layoutFullscreen) {
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800153 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
154 }
155
Setup Wizard Teamff4fecb2018-12-19 11:31:37 +0800156 registerMixin(
Setup Wizard Team67e7fef2019-03-23 08:06:48 +0800157 StatusBarMixin.class, new StatusBarMixin(this, activity.getWindow(), attrs, defStyleAttr));
158 registerMixin(SystemNavBarMixin.class, new SystemNavBarMixin(this, activity.getWindow()));
159 registerMixin(FooterBarMixin.class, new FooterBarMixin(this, attrs, defStyleAttr));
Setup Wizard Teamff4fecb2018-12-19 11:31:37 +0800160
Setup Wizard Team1ed30732019-03-14 10:00:10 +0800161 getMixin(SystemNavBarMixin.class).applyPartnerCustomizations(attrs, defStyleAttr);
162
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800163 // Override the FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_TRANSLUCENT_STATUS,
164 // FLAG_TRANSLUCENT_NAVIGATION and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN attributes of window forces
165 // showing status bar and navigation bar.
Setup Wizard Teamde9b52a2019-04-01 10:27:47 +0800166 if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
167 activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
168 activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
169 activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
170 }
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800171 }
172
173 @Override
174 protected View onInflateTemplate(LayoutInflater inflater, int template) {
175 if (template == 0) {
176 template = R.layout.partner_customization_layout;
177 }
178 return inflateTemplate(inflater, 0, template);
179 }
180
Setup Wizard Teamde9b52a2019-04-01 10:27:47 +0800181 /**
182 * {@inheritDoc}
183 *
184 * <p>This method sets all these flags before onTemplateInflated since it will be too late and get
185 * incorrect flag value on PartnerCustomizationLayout if sets them after onTemplateInflated.
186 */
187 @Override
188 protected void onBeforeTemplateInflated(AttributeSet attrs, int defStyleAttr) {
189
Setup Wizard Teamde9b52a2019-04-01 10:27:47 +0800190 // Sets default value to true since this timing
191 // before PartnerCustomization members initialization
192 usePartnerResourceAttr = true;
193
194 activity = lookupActivityFromContext(getContext());
195
Pasty Changf425dc32025-03-02 22:16:51 -0800196 LOG.atDebug(
197 "Flag of isEnhancedSetupDesignMetricsEnabled="
198 + PartnerConfigHelper.isEnhancedSetupDesignMetricsEnabled(getContext()));
199 if (PartnerConfigHelper.isEnhancedSetupDesignMetricsEnabled(getContext())) {
200 tryRegisterFragmentCallbacks(activity);
201 }
202
Setup Wizard Team75de5902020-09-22 20:34:53 +0800203 boolean isSetupFlow = WizardManagerHelper.isAnySetupWizard(activity.getIntent());
Setup Wizard Teamde9b52a2019-04-01 10:27:47 +0800204
205 TypedArray a =
206 getContext()
207 .obtainStyledAttributes(
208 attrs, R.styleable.SucPartnerCustomizationLayout, defStyleAttr, 0);
209
210 if (!a.hasValue(R.styleable.SucPartnerCustomizationLayout_sucUsePartnerResource)) {
Setup Wizard Team5b6b1b32019-04-02 13:42:22 +0800211 // TODO: Enable Log.WTF after other client already set sucUsePartnerResource.
Setup Wizard Teamf513dd22021-06-10 15:49:36 +0800212 LOG.e("Attribute sucUsePartnerResource not found in " + activity.getComponentName());
Setup Wizard Teamde9b52a2019-04-01 10:27:47 +0800213 }
214
215 usePartnerResourceAttr =
216 isSetupFlow
217 || a.getBoolean(R.styleable.SucPartnerCustomizationLayout_sucUsePartnerResource, true);
218
Setup Wizard Team8a37aa82021-04-26 10:01:19 +0800219 useDynamicColor = a.hasValue(R.styleable.SucPartnerCustomizationLayout_sucFullDynamicColor);
220 useFullDynamicColorAttr =
221 a.getBoolean(R.styleable.SucPartnerCustomizationLayout_sucFullDynamicColor, false);
222
Setup Wizard Teamde9b52a2019-04-01 10:27:47 +0800223 a.recycle();
224
Setup Wizard Teamf513dd22021-06-10 15:49:36 +0800225 LOG.atDebug(
226 "activity="
227 + activity.getClass().getSimpleName()
228 + " isSetupFlow="
229 + isSetupFlow
230 + " enablePartnerResourceLoading="
231 + enablePartnerResourceLoading()
232 + " usePartnerResourceAttr="
233 + usePartnerResourceAttr
234 + " useDynamicColor="
235 + useDynamicColor
236 + " useFullDynamicColorAttr="
237 + useFullDynamicColorAttr);
Setup Wizard Teamde9b52a2019-04-01 10:27:47 +0800238 }
239
Pasty Changf425dc32025-03-02 22:16:51 -0800240 private void printFragmentInfoAtDebug(Fragment fragment, String tag) {
241 if (fragment == null) {
242 return;
243 }
244 int fragmentId = fragment.getId();
245 String fragmentName = tryGetResourceEntryName(fragmentId);
246 LOG.atDebug(
247 tag
248 + " fragment name="
249 + fragment.getClass().getSimpleName()
250 + ", tag="
251 + fragment.getTag()
252 + ", id="
253 + fragment.getId()
254 + ", name="
255 + fragmentName);
256 }
257
258 private String tryGetResourceEntryName(int fragmentId) {
259 return (fragmentId == 0) ? "" : getResources().getResourceEntryName(fragmentId);
260 }
261
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800262 @Override
263 protected ViewGroup findContainer(int containerId) {
264 if (containerId == 0) {
265 containerId = R.id.suc_layout_content;
266 }
267 return super.findContainer(containerId);
268 }
269
270 @Override
271 protected void onAttachedToWindow() {
272 super.onAttachedToWindow();
Pasty Changcec90d02025-02-19 17:38:43 -0800273 LifecycleFragment lifecycleFragment =
274 LifecycleFragment.attachNow(activity, this::logFooterButtonMetrics);
Pasty Chang1ca08d82025-02-16 18:10:28 -0800275 if (lifecycleFragment == null) {
276 LOG.atDebug(
277 "Unable to attach lifecycle fragment to the host activity. Activity="
278 + ((activity != null) ? activity.getClass().getSimpleName() : "null"));
279 }
280
Setup Wizard Teamaa4a4b72023-10-16 04:39:29 +0000281 if (WizardManagerHelper.isAnySetupWizard(activity.getIntent())) {
Setup Wizard Team55addcd2022-01-06 23:50:39 +0800282 getViewTreeObserver().addOnWindowFocusChangeListener(windowFocusChangeListener);
283 }
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800284 getMixin(FooterBarMixin.class).onAttachedToWindow();
Setup Wizard Team1d79d002018-12-13 14:30:13 +0800285 }
286
287 @Override
288 protected void onDetachedFromWindow() {
289 super.onDetachedFromWindow();
Setup Wizard Team55addcd2022-01-06 23:50:39 +0800290 if (VERSION.SDK_INT >= Build.VERSION_CODES.Q
Setup Wizard Teamde9b52a2019-04-01 10:27:47 +0800291 && WizardManagerHelper.isAnySetupWizard(activity.getIntent())) {
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800292 FooterBarMixin footerBarMixin = getMixin(FooterBarMixin.class);
293 footerBarMixin.onDetachedFromWindow();
294 FooterButton primaryButton = footerBarMixin.getPrimaryButton();
295 FooterButton secondaryButton = footerBarMixin.getSecondaryButton();
296 PersistableBundle primaryButtonMetrics =
297 primaryButton != null
298 ? primaryButton.getMetrics("PrimaryFooterButton")
299 : PersistableBundle.EMPTY;
300 PersistableBundle secondaryButtonMetrics =
301 secondaryButton != null
302 ? secondaryButton.getMetrics("SecondaryFooterButton")
303 : PersistableBundle.EMPTY;
304
David Liu534db6a2023-02-15 06:55:44 +0000305 PersistableBundle layoutTypeMetrics =
306 (layoutTypeBundle != null) ? layoutTypeBundle : PersistableBundle.EMPTY;
307
Setup Wizard Teamd6fc4af2019-12-31 20:58:11 +0800308 PersistableBundle persistableBundle =
309 PersistableBundles.mergeBundles(
David Liu534db6a2023-02-15 06:55:44 +0000310 footerBarMixin.getLoggingMetrics(),
311 primaryButtonMetrics,
312 secondaryButtonMetrics,
313 layoutTypeMetrics);
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800314
Setup Wizard Team1d79d002018-12-13 14:30:13 +0800315 SetupMetricsLogger.logCustomEvent(
316 getContext(),
Setup Wizard Team24bb1e22019-11-08 15:22:51 +0800317 CustomEvent.create(MetricKey.get("SetupCompatMetrics", activity), persistableBundle));
Setup Wizard Team1d79d002018-12-13 14:30:13 +0800318 }
Setup Wizard Teamaa4a4b72023-10-16 04:39:29 +0000319 getViewTreeObserver().removeOnWindowFocusChangeListener(windowFocusChangeListener);
Pasty Changf425dc32025-03-02 22:16:51 -0800320
321 if (PartnerConfigHelper.isEnhancedSetupDesignMetricsEnabled(getContext())) {
322 tryUnregisterFragmentCallbacks(activity);
323 }
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800324 }
325
Pasty Chang1912cc62025-03-18 22:37:26 -0700326 private void logFooterButtonMetrics(PersistableBundle bundle) {
Pasty Changcec90d02025-02-19 17:38:43 -0800327 if (VERSION.SDK_INT >= Build.VERSION_CODES.Q
328 && activity != null
329 && WizardManagerHelper.isAnySetupWizard(activity.getIntent())
330 && PartnerConfigHelper.isEnhancedSetupDesignMetricsEnabled(getContext())) {
331 FooterBarMixin footerBarMixin = getMixin(FooterBarMixin.class);
332
333 if (footerBarMixin == null
334 || (footerBarMixin.getPrimaryButton() == null
335 && footerBarMixin.getSecondaryButton() == null)) {
336 LOG.atDebug("Skip footer button logging because no footer buttons.");
337 return;
338 }
339
340 footerBarMixin.onDetachedFromWindow();
341 FooterButton primaryButton = footerBarMixin.getPrimaryButton();
342 FooterButton secondaryButton = footerBarMixin.getSecondaryButton();
343 PersistableBundle primaryButtonMetrics =
344 primaryButton != null
345 ? primaryButton.getMetrics("PrimaryFooterButton")
346 : PersistableBundle.EMPTY;
347 PersistableBundle secondaryButtonMetrics =
348 secondaryButton != null
349 ? secondaryButton.getMetrics("SecondaryFooterButton")
350 : PersistableBundle.EMPTY;
351
352 PersistableBundle persistableBundle =
353 PersistableBundles.mergeBundles(
Pasty Chang1912cc62025-03-18 22:37:26 -0700354 footerBarMixin.getLoggingMetrics(),
355 primaryButtonMetrics,
356 secondaryButtonMetrics,
357 bundle);
Pasty Changcec90d02025-02-19 17:38:43 -0800358
359 SetupMetricsLogger.logCustomEvent(
360 getContext(),
361 CustomEvent.create(MetricKey.get("FooterButtonMetrics", activity), persistableBundle));
362 }
363 }
364
Pasty Changf425dc32025-03-02 22:16:51 -0800365 private void tryRegisterFragmentCallbacks(Activity activity) {
366 if ((activity instanceof FragmentActivity fragmentActivity)) {
367 fragmentLifecycleCallbacks =
368 new FragmentLifecycleCallbacks() {
369 @Override
370 public void onFragmentAttached(
371 @NonNull FragmentManager fm, @NonNull Fragment f, @NonNull Context context) {
372 printFragmentInfoAtDebug(f, "onFragmentAttached");
373 getMixin(FooterBarMixin.class).setFragmentInfo(f);
374 super.onFragmentAttached(fm, f, context);
375 }
376 };
377
378 fragmentActivity
379 .getSupportFragmentManager()
380 .registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true);
381 LOG.atDebug(
382 "Register the onFragmentAttached lifecycle callbacks to "
383 + activity.getClass().getSimpleName());
384 }
385 }
386
387 private void tryUnregisterFragmentCallbacks(Activity activity) {
388 if ((activity instanceof FragmentActivity fragmentActivity)) {
389 fragmentActivity
390 .getSupportFragmentManager()
391 .unregisterFragmentLifecycleCallbacks(fragmentLifecycleCallbacks);
392 }
393 }
394
David Liu534db6a2023-02-15 06:55:44 +0000395 /**
Setup Wizard Team4f5bbf42023-12-20 03:05:46 +0000396 * PartnerCustomizationLayout is a template layout for different type of GlifLayout. This method
397 * allows each type of layout to report its "GlifLayoutType".
David Liu534db6a2023-02-15 06:55:44 +0000398 */
399 public void setLayoutTypeMetrics(PersistableBundle bundle) {
400 this.layoutTypeBundle = bundle;
401 }
402
403 /** Returns a {@link PersistableBundle} contains key "GlifLayoutType". */
404 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
405 public PersistableBundle getLayoutTypeMetrics() {
406 return this.layoutTypeBundle;
407 }
408
Setup Wizard Team642e0962020-12-30 19:23:06 +0800409 public static Activity lookupActivityFromContext(Context context) {
Setup Wizard Teamaa4a4b72023-10-16 04:39:29 +0000410 return PartnerConfigHelper.lookupActivityFromContext(context);
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800411 }
412
413 /**
Setup Wizard Team67e7fef2019-03-23 08:06:48 +0800414 * Returns true if partner resource loading is enabled. If true, and other necessary conditions
415 * for loading theme attributes are met, this layout will use customized theme attributes from OEM
416 * overlays. This is intended to be used with flag-based development, to allow a flag to control
417 * the rollout of partner resource loading.
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800418 */
Setup Wizard Team67e7fef2019-03-23 08:06:48 +0800419 protected boolean enablePartnerResourceLoading() {
Setup Wizard Teamd41e3be2019-01-17 16:07:58 +0800420 return true;
421 }
422
Setup Wizard Team1ed30732019-03-14 10:00:10 +0800423 /** Returns if the current layout/activity applies partner customized configurations or not. */
Setup Wizard Team67e7fef2019-03-23 08:06:48 +0800424 public boolean shouldApplyPartnerResource() {
425 if (!enablePartnerResourceLoading()) {
426 return false;
427 }
428 if (!usePartnerResourceAttr) {
429 return false;
430 }
Setup Wizard Team3266cd82019-05-09 19:31:02 +0800431 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
Setup Wizard Team67e7fef2019-03-23 08:06:48 +0800432 return false;
433 }
434 if (!PartnerConfigHelper.get(getContext()).isAvailable()) {
435 return false;
436 }
437 return true;
Setup Wizard Team1ed30732019-03-14 10:00:10 +0800438 }
Setup Wizard Team8a37aa82021-04-26 10:01:19 +0800439
440 /**
441 * Returns {@code true} if the current layout/activity applies dynamic color. Otherwise, returns
442 * {@code false}.
443 */
444 public boolean shouldApplyDynamicColor() {
Setup Wizard Team8a37aa82021-04-26 10:01:19 +0800445 if (!BuildCompatUtils.isAtLeastS()) {
446 return false;
447 }
Pasty Chang0a439182024-11-18 03:02:38 +0000448
Setup Wizard Team8a37aa82021-04-26 10:01:19 +0800449 if (!PartnerConfigHelper.get(getContext()).isAvailable()) {
450 return false;
451 }
Pasty Chang0a439182024-11-18 03:02:38 +0000452
453 // If the dynamic theme is applied, useDynamicColor would be true and shouldApplyDynamicColor
454 // would return true.
455 if (useDynamicColor) {
456 return true;
457 }
458 if (!PartnerConfigHelper.isSetupWizardDynamicColorEnabled(getContext())) {
459 return false;
460 }
Setup Wizard Team8a37aa82021-04-26 10:01:19 +0800461 return true;
462 }
463
464 /**
465 * Returns {@code true} if the current layout/activity applies full dynamic color. Otherwise,
Pasty Changfc90bfe2024-10-07 12:01:17 +0000466 * returns {@code false}. This method combines the result of {@link #shouldApplyDynamicColor()},
467 * the value of the {@code app:sucFullDynamicColor}, and the result of {@link
468 * PartnerConfigHelper#isSetupWizardFullDynamicColorEnabled(Context)}.
Setup Wizard Team8a37aa82021-04-26 10:01:19 +0800469 */
470 public boolean useFullDynamicColor() {
Pasty Changfc90bfe2024-10-07 12:01:17 +0000471 return shouldApplyDynamicColor()
472 && (useFullDynamicColorAttr
473 || PartnerConfigHelper.isSetupWizardFullDynamicColorEnabled(getContext()));
Setup Wizard Team8a37aa82021-04-26 10:01:19 +0800474 }
Setup Wizard Team55addcd2022-01-06 23:50:39 +0800475
476 /**
Pasty Changfc90bfe2024-10-07 12:01:17 +0000477 * Sets a logging observer for {@link FooterBarMixin}. The logging observer is used to log UI
478 * events (e.g. page impressions and button clicks) on the layout and footer bar buttons.
Setup Wizard Team4f5bbf42023-12-20 03:05:46 +0000479 */
480 public void setLoggingObserver(LoggingObserver loggingObserver) {
Setup Wizard Team4f5bbf42023-12-20 03:05:46 +0000481 loggingObserver.log(new LayoutInflatedEvent(this));
Pasty Changfc90bfe2024-10-07 12:01:17 +0000482 getMixin(FooterBarMixin.class).setLoggingObserver(loggingObserver);
Setup Wizard Team4f5bbf42023-12-20 03:05:46 +0000483 }
484
485 /**
Setup Wizard Team55addcd2022-01-06 23:50:39 +0800486 * Invoke the method onFocusStatusChanged when onWindowFocusChangeListener receive onFocusChanged.
487 */
488 private void onFocusChanged(boolean hasFocus) {
489 SetupCompatServiceInvoker.get(getContext())
490 .onFocusStatusChanged(
491 FocusChangedMetricHelper.getScreenName(activity),
492 FocusChangedMetricHelper.getExtraBundle(
493 activity, PartnerCustomizationLayout.this, hasFocus));
494 }
Pasty Changf3ba27a2025-02-23 23:52:07 -0800495
496 @Override
497 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
498 // TODO: b/398407478 - Add test case for edge to edge to layout from library.
499 if (PartnerConfigHelper.isGlifExpressiveEnabled(getContext())) {
500 // Edge to edge extend the footer bar padding bottom to the navigation bar height.
501 if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && insets.getSystemWindowInsetBottom() > 0) {
502 LOG.atDebug("NavigationBarHeight: " + insets.getSystemWindowInsetBottom());
503 FooterBarMixin footerBarMixin = getMixin(FooterBarMixin.class);
504 LinearLayout buttonContainer = footerBarMixin.getButtonContainer();
505 if (footerBarMixin != null && footerBarMixin.getButtonContainer() != null) {
506 if (PartnerConfigHelper.get(getContext())
507 .isPartnerConfigAvailable(PartnerConfig.CONFIG_FOOTER_BUTTON_PADDING_BOTTOM)) {
508 footerBarPaddingBottom =
509 (int)
510 PartnerConfigHelper.get(getContext())
511 .getDimension(
512 getContext(), PartnerConfig.CONFIG_FOOTER_BUTTON_PADDING_BOTTOM);
513 }
514 // Adjust footer bar padding to account for the navigation bar, ensuring
515 // it extends to the bottom of the screen and with proper bottom padding.
516 buttonContainer.setPadding(
517 buttonContainer.getPaddingLeft(),
518 buttonContainer.getPaddingTop(),
519 buttonContainer.getPaddingRight(),
520 footerBarPaddingBottom + insets.getSystemWindowInsetBottom());
521 }
522 }
523 }
524 return super.onApplyWindowInsets(insets);
525 }
Setup Wizard Team8ccc9e62018-11-28 13:33:48 +0800526}