1 /*
2  * Copyright (C) 2013 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.settings;
18 
19 import android.app.Activity;
20 import android.content.DialogInterface;
21 import android.content.res.Resources;
22 import android.graphics.Bitmap;
23 import android.graphics.BitmapFactory;
24 import android.graphics.drawable.Drawable;
25 import android.os.Bundle;
26 import android.os.SystemProperties;
27 import android.text.TextUtils;
28 import android.view.Gravity;
29 import android.view.View;
30 import android.widget.ImageView;
31 import android.widget.TextView;
32 
33 import androidx.annotation.VisibleForTesting;
34 import androidx.appcompat.app.AlertDialog;
35 
36 import java.util.Locale;
37 
38 /**
39  * {@link Activity} that displays regulatory information for the "Regulatory information"
40  * preference item, and when "*#07#" is dialed on the Phone keypad. To enable this feature,
41  * set the "config_show_regulatory_info" boolean to true in a device overlay resource, and in the
42  * same overlay, either add a drawable named "regulatory_info.png" containing a graphical version
43  * of the required regulatory info (If ro.bootloader.hardware.sku property is set use
44  * "regulatory_info_<sku>.png where sku is ro.bootloader.hardware.sku property value in lowercase"),
45  * or add a string resource named "regulatory_info_text" with an HTML version of the required
46  * information (text will be centered in the dialog).
47  */
48 public class RegulatoryInfoDisplayActivity extends Activity implements
49         DialogInterface.OnDismissListener {
50 
51     private final String REGULATORY_INFO_RESOURCE = "regulatory_info";
52     private static final String DEFAULT_REGULATORY_INFO_FILEPATH =
53             "/data/misc/elabel/regulatory_info.png";
54     private static final String REGULATORY_INFO_FILEPATH_TEMPLATE =
55             "/data/misc/elabel/regulatory_info_%s.png";
56 
57     /**
58      * Display the regulatory info graphic in a dialog window.
59      */
60     @Override
onCreate(Bundle savedInstanceState)61     protected void onCreate(Bundle savedInstanceState) {
62         super.onCreate(savedInstanceState);
63         AlertDialog.Builder builder = new AlertDialog.Builder(this)
64                 .setTitle(R.string.regulatory_labels)
65                 .setOnDismissListener(this)
66                 .setPositiveButton(android.R.string.ok, null /* onClickListener */);
67 
68         boolean regulatoryInfoDrawableExists = false;
69 
70         final String regulatoryInfoFile = getRegulatoryInfoImageFileName();
71         final Bitmap regulatoryInfoBitmap = BitmapFactory.decodeFile(regulatoryInfoFile);
72 
73         if (regulatoryInfoBitmap != null) {
74             regulatoryInfoDrawableExists = true;
75         }
76 
77         int resId = 0;
78         if (!regulatoryInfoDrawableExists) {
79             resId = getResourceId();
80         }
81         if (resId != 0) {
82             try {
83                 Drawable d = getDrawable(resId);
84                 // set to false if the width or height is <= 2
85                 // (missing PNG can return an empty 2x2 pixel Drawable)
86                 regulatoryInfoDrawableExists = (d.getIntrinsicWidth() > 2
87                         && d.getIntrinsicHeight() > 2);
88             } catch (Resources.NotFoundException ignored) {
89                 regulatoryInfoDrawableExists = false;
90             }
91         }
92 
93         CharSequence regulatoryText = getResources()
94                 .getText(R.string.regulatory_info_text);
95 
96         if (regulatoryInfoDrawableExists) {
97             View view = getLayoutInflater().inflate(R.layout.regulatory_info, null);
98             ImageView image = view.findViewById(R.id.regulatoryInfo);
99             if (regulatoryInfoBitmap != null) {
100                 image.setImageBitmap(regulatoryInfoBitmap);
101             } else {
102                 image.setImageResource(resId);
103             }
104             builder.setView(view);
105             builder.show();
106         } else if (regulatoryText.length() > 0) {
107             builder.setMessage(regulatoryText);
108             AlertDialog dialog = builder.show();
109             // we have to show the dialog first, or the setGravity() call will throw a NPE
110             TextView messageText = (TextView) dialog.findViewById(android.R.id.message);
111             messageText.setGravity(Gravity.CENTER);
112         } else {
113             // neither drawable nor text resource exists, finish activity
114             finish();
115         }
116     }
117 
118     @VisibleForTesting
getResourceId()119     int getResourceId() {
120         // Use regulatory_info by default.
121         int resId = getResources().getIdentifier(
122                 REGULATORY_INFO_RESOURCE, "drawable", getPackageName());
123 
124         // When hardware sku property exists, use regulatory_info_<sku> resource if valid.
125         final String sku = getSku();
126         if (!TextUtils.isEmpty(sku)) {
127             String regulatory_info_res = REGULATORY_INFO_RESOURCE + "_" + sku.toLowerCase();
128             int id = getResources().getIdentifier(
129                     regulatory_info_res, "drawable", getPackageName());
130             if (id != 0) {
131                 resId = id;
132             }
133         }
134 
135         // When hardware coo property exists, use regulatory_info_<sku>_<coo> resource if valid.
136         final String coo = getCoo();
137         if (!TextUtils.isEmpty(coo) && !TextUtils.isEmpty(sku)) {
138             final String regulatory_info_coo_res =
139                     REGULATORY_INFO_RESOURCE + "_" + sku.toLowerCase() + "_" + coo.toLowerCase();
140             final int id = getResources().getIdentifier(
141                     regulatory_info_coo_res, "drawable", getPackageName());
142             if (id != 0) {
143                 resId = id;
144             }
145         }
146         return resId;
147     }
148 
149     @Override
onDismiss(DialogInterface dialog)150     public void onDismiss(DialogInterface dialog) {
151         finish();   // close the activity
152     }
153 
getCoo()154     private String getCoo() {
155         return SystemProperties.get("ro.boot.hardware.coo", "");
156     }
157 
getSku()158     private String getSku() {
159         return SystemProperties.get("ro.boot.hardware.sku", "");
160     }
161 
getRegulatoryInfoImageFileName()162     private String getRegulatoryInfoImageFileName() {
163         final String sku = getSku();
164         if (TextUtils.isEmpty(sku)) {
165             return DEFAULT_REGULATORY_INFO_FILEPATH;
166         } else {
167             return String.format(Locale.US, REGULATORY_INFO_FILEPATH_TEMPLATE,
168                     sku.toLowerCase());
169         }
170     }
171 }
172