1 /* 2 * Copyright (C) 2024 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.setupcompat.util; 18 19 import android.annotation.SuppressLint; 20 import android.content.Context; 21 import android.content.res.Resources; 22 import android.content.res.Resources.NotFoundException; 23 import android.os.Build; 24 import android.os.Build.VERSION_CODES; 25 import android.view.WindowManager; 26 import android.view.WindowMetrics; 27 import androidx.annotation.LayoutRes; 28 import com.google.android.setupcompat.partnerconfig.PartnerConfig; 29 import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper; 30 31 /** 32 * A helper class to support force two pane feature on portrait orientation. This will inflate the 33 * layout from xml resource which concatenates with _two_pane suffix. 34 */ 35 public final class ForceTwoPaneHelper { 36 37 // Refer Support different screen sizes as guideline that any device that the width >= 840 will 38 // consider as large screen, b/322117552#comment15 mentioned that the apply 2 pane layouts based 39 // on width >= 840dp as screen breakpoints. 40 // 41 // https://developer.android.com/guide/topics/large-screens/support-different-screen-sizes 42 private static final int DEFAULT_ADAPT_WINDOW_WIDTH = 840; 43 44 private static final Logger LOG = new Logger("ForceTwoPaneHelper"); 45 46 /** A string to be a suffix of resource name which is associating to force two pane feature. */ 47 public static final String FORCE_TWO_PANE_SUFFIX = "_two_pane"; 48 49 /** 50 * Returns true to indicate the forced two pane feature is enabled, otherwise, returns false. This 51 * feature is supported from Sdk U while the feature enabled from SUW side. 52 */ isForceTwoPaneEnable(Context context)53 public static boolean isForceTwoPaneEnable(Context context) { 54 return Build.VERSION.SDK_INT >= VERSION_CODES.UPSIDE_DOWN_CAKE 55 && PartnerConfigHelper.isForceTwoPaneEnabled(context); 56 } 57 58 /** 59 * Returns true if satisfied 1) enable force two-pane feature, 2) portrait mode, 3) width >= 60 * setup_compat_two_pane_adapt_window_width, forced to show in two-pane style, otherwise, returns 61 * false. 62 */ shouldForceTwoPane(Context context)63 public static boolean shouldForceTwoPane(Context context) { 64 if (!isForceTwoPaneEnable(context)) { 65 return false; 66 } 67 68 if (context == null) { 69 return false; 70 } 71 72 WindowManager windowManager = context.getSystemService(WindowManager.class); 73 if (windowManager != null) { 74 WindowMetrics windowMetrics = windowManager.getCurrentWindowMetrics(); 75 if (windowMetrics.getBounds().width() > windowMetrics.getBounds().height()) { 76 // Return false for portrait mode 77 return false; 78 } 79 80 int widthInDp = (int) (windowMetrics.getBounds().width() / windowMetrics.getDensity()); 81 int adaptWindowWidth = 82 PartnerConfigHelper.get(context) 83 .getInteger( 84 context, 85 PartnerConfig.CONFIG_TWO_PANE_ADAPT_WINDOW_WIDTH, 86 DEFAULT_ADAPT_WINDOW_WIDTH); 87 return widthInDp >= adaptWindowWidth; 88 } 89 90 return false; 91 } 92 93 /** 94 * Returns a layout which is picking up from the layout resources with _two_pane suffix. Fallback 95 * to origin resource id if the layout resource not available. For example, pass an 96 * glif_sud_template resource id and it will return glif_sud_template_two_pane resource id if it 97 * available. 98 */ 99 @LayoutRes 100 @SuppressLint("DiscouragedApi") getForceTwoPaneStyleLayout(Context context, int template)101 public static int getForceTwoPaneStyleLayout(Context context, int template) { 102 if (!isForceTwoPaneEnable(context)) { 103 return template; 104 } 105 106 if (template == Resources.ID_NULL) { 107 return template; 108 } 109 110 try { 111 String layoutResName = context.getResources().getResourceEntryName(template); 112 int twoPaneLayoutId = 113 context 114 .getResources() 115 .getIdentifier( 116 layoutResName + FORCE_TWO_PANE_SUFFIX, "layout", context.getPackageName()); 117 if (twoPaneLayoutId != Resources.ID_NULL) { 118 return twoPaneLayoutId; 119 } 120 } catch (NotFoundException ignore) { 121 LOG.w("Resource id 0x" + Integer.toHexString(template) + " is not found"); 122 } 123 124 return template; 125 } 126 ForceTwoPaneHelper()127 private ForceTwoPaneHelper() {} 128 } 129