blob: bc5a2c05e379c8079b100b799817392720d0c6ce [file] [log] [blame]
Tony Mantlere92cf6d2015-11-10 10:40:14 -08001/*
2 * Copyright (C) 2015 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.android.settingslib;
18
Fan Zhangf7802ea2018-08-28 15:15:19 -070019import static android.content.Context.TELEPHONY_SERVICE;
20
Tony Mantlere92cf6d2015-11-10 10:40:14 -080021import android.content.Context;
22import android.content.Intent;
23import android.content.pm.ApplicationInfo;
24import android.content.pm.PackageManager;
25import android.content.pm.ResolveInfo;
26import android.os.Build;
jeffreyhuangd32e79f2017-11-10 13:01:12 -080027import android.system.Os;
28import android.system.StructUtsname;
Fan Zhang75ee8d12016-07-06 12:19:34 -070029import android.telephony.PhoneNumberUtils;
30import android.telephony.SubscriptionInfo;
31import android.telephony.TelephonyManager;
Tony Mantlere92cf6d2015-11-10 10:40:14 -080032import android.text.TextUtils;
33import android.text.format.DateFormat;
34import android.util.Log;
Fan Zhangf7802ea2018-08-28 15:15:19 -070035
Aurimas Liutikasfd52c142018-04-17 09:50:46 -070036import androidx.annotation.VisibleForTesting;
Tony Mantlere92cf6d2015-11-10 10:40:14 -080037
38import java.io.BufferedReader;
39import java.io.FileReader;
40import java.io.IOException;
41import java.text.ParseException;
42import java.text.SimpleDateFormat;
43import java.util.Date;
44import java.util.List;
45import java.util.Locale;
46import java.util.regex.Matcher;
47import java.util.regex.Pattern;
48
49public class DeviceInfoUtils {
50 private static final String TAG = "DeviceInfoUtils";
51
Tony Mantlere92cf6d2015-11-10 10:40:14 -080052 private static final String FILENAME_MSV = "/sys/board_properties/soc/msv";
53
54 /**
55 * Reads a line from the specified file.
56 * @param filename the file to read from
57 * @return the first line, if any.
58 * @throws IOException if the file couldn't be read
59 */
60 private static String readLine(String filename) throws IOException {
61 BufferedReader reader = new BufferedReader(new FileReader(filename), 256);
62 try {
63 return reader.readLine();
64 } finally {
65 reader.close();
66 }
67 }
68
jeffreyhuangd32e79f2017-11-10 13:01:12 -080069 public static String getFormattedKernelVersion(Context context) {
70 return formatKernelVersion(context, Os.uname());
Tony Mantlere92cf6d2015-11-10 10:40:14 -080071 }
72
jeffreyhuangd32e79f2017-11-10 13:01:12 -080073 @VisibleForTesting
74 static String formatKernelVersion(Context context, StructUtsname uname) {
75 if (uname == null) {
76 return context.getString(R.string.status_unavailable);
Tony Mantlere92cf6d2015-11-10 10:40:14 -080077 }
jeffreyhuangd32e79f2017-11-10 13:01:12 -080078 // Example:
79 // 4.9.29-g958411d
80 // #1 SMP PREEMPT Wed Jun 7 00:06:03 CST 2017
81 final String VERSION_REGEX =
82 "(#\\d+) " + /* group 1: "#1" */
83 "(?:.*?)?" + /* ignore: optional SMP, PREEMPT, and any CONFIG_FLAGS */
84 "((Sun|Mon|Tue|Wed|Thu|Fri|Sat).+)"; /* group 2: "Thu Jun 28 11:02:39 PDT 2012" */
85 Matcher m = Pattern.compile(VERSION_REGEX).matcher(uname.version);
86 if (!m.matches()) {
87 Log.e(TAG, "Regex did not match on uname version " + uname.version);
88 return context.getString(R.string.status_unavailable);
89 }
90
91 // Example output:
92 // 4.9.29-g958411d
93 // #1 Wed Jun 7 00:06:03 CST 2017
94 return new StringBuilder().append(uname.release)
95 .append("\n")
96 .append(m.group(1))
97 .append(" ")
98 .append(m.group(2)).toString();
Tony Mantlere92cf6d2015-11-10 10:40:14 -080099 }
100
101 /**
102 * Returns " (ENGINEERING)" if the msv file has a zero value, else returns "".
103 * @return a string to append to the model number description.
104 */
105 public static String getMsvSuffix() {
106 // Production devices should have a non-zero value. If we can't read it, assume it's a
107 // production device so that we don't accidentally show that it's an ENGINEERING device.
108 try {
109 String msv = readLine(FILENAME_MSV);
110 // Parse as a hex number. If it evaluates to a zero, then it's an engineering build.
111 if (Long.parseLong(msv, 16) == 0) {
112 return " (ENGINEERING)";
113 }
114 } catch (IOException|NumberFormatException e) {
115 // Fail quietly, as the file may not exist on some devices, or may be unreadable
116 }
117 return "";
118 }
119
120 public static String getFeedbackReporterPackage(Context context) {
121 final String feedbackReporter =
122 context.getResources().getString(R.string.oem_preferred_feedback_reporter);
123 if (TextUtils.isEmpty(feedbackReporter)) {
124 // Reporter not configured. Return.
125 return feedbackReporter;
126 }
127 // Additional checks to ensure the reporter is on system image, and reporter is
128 // configured to listen to the intent. Otherwise, dont show the "send feedback" option.
129 final Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
130
131 PackageManager pm = context.getPackageManager();
132 List<ResolveInfo> resolvedPackages =
133 pm.queryIntentActivities(intent, PackageManager.GET_RESOLVED_FILTER);
134 for (ResolveInfo info : resolvedPackages) {
135 if (info.activityInfo != null) {
136 if (!TextUtils.isEmpty(info.activityInfo.packageName)) {
137 try {
138 ApplicationInfo ai =
139 pm.getApplicationInfo(info.activityInfo.packageName, 0);
140 if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
141 // Package is on the system image
142 if (TextUtils.equals(
143 info.activityInfo.packageName, feedbackReporter)) {
144 return feedbackReporter;
145 }
146 }
147 } catch (PackageManager.NameNotFoundException e) {
148 // No need to do anything here.
149 }
150 }
151 }
152 }
153 return null;
154 }
155
156 public static String getSecurityPatch() {
157 String patch = Build.VERSION.SECURITY_PATCH;
158 if (!"".equals(patch)) {
159 try {
160 SimpleDateFormat template = new SimpleDateFormat("yyyy-MM-dd");
161 Date patchDate = template.parse(patch);
162 String format = DateFormat.getBestDateTimePattern(Locale.getDefault(), "dMMMMyyyy");
163 patch = DateFormat.format(format, patchDate).toString();
164 } catch (ParseException e) {
165 // broken parse; fall through and use the raw string
166 }
167 return patch;
168 } else {
169 return null;
170 }
171 }
172
Fan Zhang75ee8d12016-07-06 12:19:34 -0700173 public static String getFormattedPhoneNumber(Context context, SubscriptionInfo subscriptionInfo) {
174 String formattedNumber = null;
175 if (subscriptionInfo != null) {
176 final TelephonyManager telephonyManager =
177 (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
178 final String rawNumber =
179 telephonyManager.getLine1Number(subscriptionInfo.getSubscriptionId());
180 if (!TextUtils.isEmpty(rawNumber)) {
181 formattedNumber = PhoneNumberUtils.formatNumber(rawNumber);
182 }
183
184 }
185 return formattedNumber;
186 }
187
188 public static String getFormattedPhoneNumbers(Context context,
189 List<SubscriptionInfo> subscriptionInfo) {
190 StringBuilder sb = new StringBuilder();
191 if (subscriptionInfo != null) {
192 final TelephonyManager telephonyManager =
193 (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
194 final int count = subscriptionInfo.size();
195 for (int i = 0; i < count; i++) {
196 final String rawNumber = telephonyManager.getLine1Number(
197 subscriptionInfo.get(i).getSubscriptionId());
198 if (!TextUtils.isEmpty(rawNumber)) {
199 sb.append(PhoneNumberUtils.formatNumber(rawNumber));
200 if (i < count - 1) {
201 sb.append("\n");
202 }
203 }
204 }
205 }
206 return sb.toString();
207 }
208
Tony Mantlere92cf6d2015-11-10 10:40:14 -0800209}