1 /*
2  * Copyright (C) 2019 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.google.android.setupdesign.util;
18 
19 import android.app.Activity;
20 import android.content.Context;
21 import android.content.res.TypedArray;
22 import android.os.Build;
23 import android.view.Gravity;
24 import android.view.View;
25 import com.google.android.setupcompat.PartnerCustomizationLayout;
26 import com.google.android.setupcompat.internal.TemplateLayout;
27 import com.google.android.setupcompat.partnerconfig.PartnerConfig;
28 import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper;
29 import com.google.android.setupcompat.util.WizardManagerHelper;
30 import com.google.android.setupdesign.GlifLayout;
31 import com.google.android.setupdesign.R;
32 import java.util.Locale;
33 
34 /** The helper reads styles from the partner configurations. */
35 public final class PartnerStyleHelper {
36 
37   private static final String TAG = "PartnerStyleHelper";
38   /**
39    * Returns the partner configuration of layout gravity, usually apply to widgets in header area.
40    */
getLayoutGravity(Context context)41   public static int getLayoutGravity(Context context) {
42     String gravity =
43         PartnerConfigHelper.get(context).getString(context, PartnerConfig.CONFIG_LAYOUT_GRAVITY);
44     if (gravity == null) {
45       return 0;
46     }
47     switch (gravity.toLowerCase(Locale.ROOT)) {
48       case "center":
49         return Gravity.CENTER;
50       case "start":
51         return Gravity.START;
52       default:
53         return 0;
54     }
55   }
56 
57   /** Returns the given layout if apply partner heavy theme. */
isPartnerHeavyThemeLayout(TemplateLayout layout)58   public static boolean isPartnerHeavyThemeLayout(TemplateLayout layout) {
59     if (!(layout instanceof GlifLayout)) {
60       return false;
61     }
62     return ((GlifLayout) layout).shouldApplyPartnerHeavyThemeResource();
63   }
64 
65   /** Returns the given layout if apply partner light theme. */
isPartnerLightThemeLayout(TemplateLayout layout)66   public static boolean isPartnerLightThemeLayout(TemplateLayout layout) {
67     if (!(layout instanceof PartnerCustomizationLayout)) {
68       return false;
69     }
70     return ((PartnerCustomizationLayout) layout).shouldApplyPartnerResource();
71   }
72 
73   /**
74    * Returns if the current layout/activity of the given {@code view} applies partner customized
75    * configurations or not.
76    *
77    * @param view A PartnerCustomizationLayout view, would be used to get the activity and context.
78    */
shouldApplyPartnerResource(View view)79   public static boolean shouldApplyPartnerResource(View view) {
80     if (view == null) {
81       return false;
82     }
83     if (view instanceof PartnerCustomizationLayout) {
84       return isPartnerLightThemeLayout((PartnerCustomizationLayout) view);
85     }
86     return shouldApplyPartnerResource(view.getContext());
87   }
88 
shouldApplyPartnerResource(Context context)89   private static boolean shouldApplyPartnerResource(Context context) {
90     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
91       return false;
92     }
93 
94     if (!PartnerConfigHelper.get(context).isAvailable()) {
95       return false;
96     }
97 
98     Activity activity = null;
99     try {
100       activity = PartnerCustomizationLayout.lookupActivityFromContext(context);
101       if (activity != null) {
102         TemplateLayout layout = findLayoutFromActivity(activity);
103         if (layout instanceof PartnerCustomizationLayout) {
104           return ((PartnerCustomizationLayout) layout).shouldApplyPartnerResource();
105         }
106       }
107     } catch (IllegalArgumentException | ClassCastException ex) {
108       // fall through
109     }
110 
111     // try best to get partner resource settings from attrs
112     boolean isSetupFlow = false;
113     if (activity != null) {
114       isSetupFlow = WizardManagerHelper.isAnySetupWizard(activity.getIntent());
115     }
116     TypedArray a = context.obtainStyledAttributes(new int[] {R.attr.sucUsePartnerResource});
117     boolean usePartnerResource = a.getBoolean(0, true);
118     a.recycle();
119 
120     return isSetupFlow || usePartnerResource;
121   }
122 
123   /**
124    * Returns if the current layout/activity applies heavy partner customized configurations or not.
125    *
126    * @param view A view would be used to get the activity and context.
127    */
shouldApplyPartnerHeavyThemeResource(View view)128   public static boolean shouldApplyPartnerHeavyThemeResource(View view) {
129     if (view == null) {
130       return false;
131     }
132     if (view instanceof GlifLayout) {
133       return isPartnerHeavyThemeLayout((GlifLayout) view);
134     }
135     return shouldApplyPartnerHeavyThemeResource(view.getContext());
136   }
137 
shouldApplyPartnerHeavyThemeResource(Context context)138   static boolean shouldApplyPartnerHeavyThemeResource(Context context) {
139     try {
140       Activity activity = PartnerCustomizationLayout.lookupActivityFromContext(context);
141       TemplateLayout layout = findLayoutFromActivity(activity);
142       if (layout instanceof GlifLayout) {
143         return ((GlifLayout) layout).shouldApplyPartnerHeavyThemeResource();
144       }
145     } catch (IllegalArgumentException | ClassCastException ex) {
146       // fall through
147     }
148 
149     // try best to get partner resource settings from attr
150     TypedArray a = context.obtainStyledAttributes(new int[] {R.attr.sudUsePartnerHeavyTheme});
151     boolean usePartnerHeavyTheme = a.getBoolean(0, false);
152     a.recycle();
153     usePartnerHeavyTheme =
154         usePartnerHeavyTheme || PartnerConfigHelper.shouldApplyExtendedPartnerConfig(context);
155 
156     return shouldApplyPartnerResource(context) && usePartnerHeavyTheme;
157   }
158 
159   /**
160    * Returns if the current layout/activity applies dynamic color configurations or not.
161    *
162    * @param view A GlifLayout view would be used to get the activity and context.
163    */
useDynamicColor(View view)164   public static boolean useDynamicColor(View view) {
165     if (view == null) {
166       return false;
167     }
168     return getDynamicColorAttributeFromTheme(view.getContext());
169   }
170 
getDynamicColorAttributeFromTheme(Context context)171   static boolean getDynamicColorAttributeFromTheme(Context context) {
172     try {
173       Activity activity = PartnerCustomizationLayout.lookupActivityFromContext(context);
174       TemplateLayout layout = findLayoutFromActivity(activity);
175       if (layout instanceof GlifLayout) {
176         return ((GlifLayout) layout).shouldApplyDynamicColor();
177       }
178     } catch (IllegalArgumentException | ClassCastException ex) {
179       // fall through
180     }
181 
182     // try best to get dynamic color settings from attr
183     TypedArray a = context.obtainStyledAttributes(new int[] {R.attr.sucFullDynamicColor});
184     boolean useDynamicColorTheme =
185         a.hasValue(
186             com.google
187                 .android
188                 .setupcompat
189                 .R
190                 .styleable
191                 .SucPartnerCustomizationLayout_sucFullDynamicColor);
192     a.recycle();
193 
194     return useDynamicColorTheme;
195   }
196 
findLayoutFromActivity(Activity activity)197   private static TemplateLayout findLayoutFromActivity(Activity activity) {
198     if (activity == null) {
199       return null;
200     }
201     // This only worked after activity setContentView, otherwise it will return null
202     View rootView = activity.findViewById(R.id.suc_layout_status);
203     return rootView != null ? (TemplateLayout) rootView.getParent() : null;
204   }
205 
PartnerStyleHelper()206   private PartnerStyleHelper() {}
207 }
208