1 /*
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 
17 package com.android.tv.settings.about;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.net.ConnectivityManager;
24 import android.os.Build;
25 import android.os.Bundle;
26 import android.os.PersistableBundle;
27 import android.os.SELinux;
28 import android.os.SystemClock;
29 import android.os.SystemProperties;
30 import android.os.UserManager;
31 import android.provider.Settings;
32 import android.support.annotation.Nullable;
33 import android.support.v17.preference.LeanbackPreferenceFragment;
34 import android.support.v17.preference.LeanbackSettingsFragment;
35 import android.support.v4.content.LocalBroadcastManager;
36 import android.support.v7.preference.Preference;
37 import android.support.v7.preference.PreferenceScreen;
38 import android.telephony.CarrierConfigManager;
39 import android.text.TextUtils;
40 import android.util.Log;
41 import android.widget.Toast;
42 
43 import com.android.internal.telephony.TelephonyProperties;
44 import com.android.settingslib.DeviceInfoUtils;
45 import com.android.tv.settings.LongClickPreference;
46 import com.android.tv.settings.PreferenceUtils;
47 import com.android.tv.settings.R;
48 import com.android.tv.settings.name.DeviceManager;
49 
50 public class AboutFragment extends LeanbackPreferenceFragment implements
51         LongClickPreference.OnLongClickListener {
52     private static final String TAG = "AboutFragment";
53 
54     private static final String KEY_MANUAL = "manual";
55     private static final String KEY_REGULATORY_INFO = "regulatory_info";
56     private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings";
57     private static final String PROPERTY_URL_SAFETYLEGAL = "ro.url.safetylegal";
58     private static final String PROPERTY_SELINUX_STATUS = "ro.build.selinux";
59     private static final String KEY_KERNEL_VERSION = "kernel_version";
60     private static final String KEY_BUILD_NUMBER = "build_number";
61     private static final String KEY_DEVICE_MODEL = "device_model";
62     private static final String KEY_SELINUX_STATUS = "selinux_status";
63     private static final String KEY_BASEBAND_VERSION = "baseband_version";
64     private static final String KEY_FIRMWARE_VERSION = "firmware_version";
65     private static final String KEY_SECURITY_PATCH = "security_patch";
66     private static final String KEY_UPDATE_SETTING = "additional_system_update_settings";
67     private static final String KEY_EQUIPMENT_ID = "fcc_equipment_id";
68     private static final String PROPERTY_EQUIPMENT_ID = "ro.ril.fccid";
69     private static final String KEY_DEVICE_FEEDBACK = "device_feedback";
70     private static final String KEY_SAFETY_LEGAL = "safetylegal";
71     private static final String KEY_DEVICE_NAME = "device_name";
72     private static final String KEY_RESTART = "restart";
73 
74     static final int TAPS_TO_BE_A_DEVELOPER = 7;
75 
76     long[] mHits = new long[3];
77     int mDevHitCountdown;
78     Toast mDevHitToast;
79 
80     private UserManager mUm;
81 
82     private final BroadcastReceiver mDeviceNameReceiver = new BroadcastReceiver() {
83         @Override
84         public void onReceive(Context context, Intent intent) {
85             refreshDeviceName();
86         }
87     };
88 
newInstance()89     public static AboutFragment newInstance() {
90         return new AboutFragment();
91     }
92 
93     @Override
onCreate(Bundle savedInstanceState)94     public void onCreate(Bundle savedInstanceState) {
95         mUm = UserManager.get(getActivity());
96 
97         super.onCreate(savedInstanceState);
98     }
99 
100     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)101     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
102         setPreferencesFromResource(R.xml.device_info_settings, null);
103         final PreferenceScreen screen = getPreferenceScreen();
104 
105         refreshDeviceName();
106         final Preference deviceNamePref = findPreference(KEY_DEVICE_NAME);
107         PreferenceUtils.resolveSystemActivityOrRemove(getActivity(), screen, deviceNamePref, 0);
108 
109         final Preference firmwareVersionPref = findPreference(KEY_FIRMWARE_VERSION);
110         firmwareVersionPref.setSummary(Build.VERSION.RELEASE);
111         firmwareVersionPref.setEnabled(true);
112 
113         final Preference securityPatchPref = findPreference(KEY_SECURITY_PATCH);
114         final String patch = DeviceInfoUtils.getSecurityPatch();
115         if (!TextUtils.isEmpty(patch)) {
116             securityPatchPref.setSummary(patch);
117         } else {
118             removePreference(securityPatchPref);
119         }
120 
121         final LongClickPreference restartPref = (LongClickPreference) findPreference(KEY_RESTART);
122         restartPref.setLongClickListener(this);
123 
124         findPreference(KEY_BASEBAND_VERSION).setSummary(
125                 getSystemPropertySummary(TelephonyProperties.PROPERTY_BASEBAND_VERSION));
126         findPreference(KEY_DEVICE_MODEL).setSummary(Build.MODEL + DeviceInfoUtils.getMsvSuffix());
127         findPreference(KEY_EQUIPMENT_ID)
128                 .setSummary(getSystemPropertySummary(PROPERTY_EQUIPMENT_ID));
129 
130         final Preference buildNumberPref = findPreference(KEY_BUILD_NUMBER);
131         buildNumberPref.setSummary(Build.DISPLAY);
132         buildNumberPref.setEnabled(true);
133         findPreference(KEY_KERNEL_VERSION).setSummary(DeviceInfoUtils.getFormattedKernelVersion());
134 
135         final Preference selinuxPref = findPreference(KEY_SELINUX_STATUS);
136         if (!SELinux.isSELinuxEnabled()) {
137             selinuxPref.setSummary(R.string.selinux_status_disabled);
138         } else if (!SELinux.isSELinuxEnforced()) {
139             selinuxPref.setSummary(R.string.selinux_status_permissive);
140         }
141 
142         // Remove selinux information if property is not present
143         if (TextUtils.isEmpty(SystemProperties.get(PROPERTY_SELINUX_STATUS))) {
144             removePreference(selinuxPref);
145         }
146 
147         // Remove Safety information preference if PROPERTY_URL_SAFETYLEGAL is not set
148         if (TextUtils.isEmpty(SystemProperties.get(PROPERTY_URL_SAFETYLEGAL))) {
149             removePreference(findPreference(KEY_SAFETY_LEGAL));
150         }
151 
152         // Remove Equipment id preference if FCC ID is not set by RIL
153         if (TextUtils.isEmpty(SystemProperties.get(PROPERTY_EQUIPMENT_ID))) {
154             removePreference(findPreference(KEY_EQUIPMENT_ID));
155         }
156 
157         // Remove Baseband version if wifi-only device
158         if (isWifiOnly(getActivity())) {
159             removePreference(findPreference(KEY_BASEBAND_VERSION));
160         }
161 
162         // Dont show feedback option if there is no reporter.
163         if (TextUtils.isEmpty(DeviceInfoUtils.getFeedbackReporterPackage(getActivity()))) {
164             removePreference(findPreference(KEY_DEVICE_FEEDBACK));
165         }
166 
167         final Preference updateSettingsPref = findPreference(KEY_SYSTEM_UPDATE_SETTINGS);
168         if (mUm.isAdminUser()) {
169             PreferenceUtils.resolveSystemActivityOrRemove(getActivity(), screen,
170                     updateSettingsPref, PreferenceUtils.FLAG_SET_TITLE);
171         } else if (updateSettingsPref != null) {
172             // Remove for secondary users
173             removePreference(updateSettingsPref);
174         }
175 
176         // Read platform settings for additional system update setting
177         if (!getResources().getBoolean(R.bool.config_additional_system_update_setting_enable)) {
178             removePreference(findPreference(KEY_UPDATE_SETTING));
179         }
180 
181         // Remove manual entry if none present.
182         if (!getResources().getBoolean(R.bool.config_show_manual)) {
183             removePreference(findPreference(KEY_MANUAL));
184         }
185 
186         // Remove regulatory information if none present.
187         final Preference regulatoryPref = findPreference(KEY_REGULATORY_INFO);
188         PreferenceUtils.resolveSystemActivityOrRemove(getActivity(), screen, regulatoryPref, 0);
189     }
190 
removePreference(@ullable Preference preference)191     private void removePreference(@Nullable Preference preference) {
192         if (preference != null) {
193             getPreferenceScreen().removePreference(preference);
194         }
195     }
196 
197     @Override
onStart()198     public void onStart() {
199         super.onStart();
200         refreshDeviceName();
201 
202         LocalBroadcastManager.getInstance(getContext()).registerReceiver(mDeviceNameReceiver,
203                 new IntentFilter(DeviceManager.ACTION_DEVICE_NAME_UPDATE));
204     }
205 
206     @Override
onResume()207     public void onResume() {
208         super.onResume();
209         final boolean developerEnabled = Settings.Global.getInt(getActivity().getContentResolver(),
210                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
211                 android.os.Build.TYPE.equals("eng") ? 1 : 0) == 1;
212         mDevHitCountdown = developerEnabled ? -1 : TAPS_TO_BE_A_DEVELOPER;
213         mDevHitToast = null;
214     }
215 
216     @Override
onStop()217     public void onStop() {
218         super.onStop();
219         LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mDeviceNameReceiver);
220     }
221 
refreshDeviceName()222     private void refreshDeviceName() {
223         final Preference deviceNamePref = findPreference(KEY_DEVICE_NAME);
224         if (deviceNamePref != null) {
225             deviceNamePref.setSummary(DeviceManager.getDeviceName(getActivity()));
226         }
227     }
228 
229     @Override
onPreferenceLongClick(Preference preference)230     public boolean onPreferenceLongClick(Preference preference) {
231         if (TextUtils.equals(preference.getKey(), KEY_RESTART)) {
232             if (getCallbackFragment() instanceof LeanbackSettingsFragment) {
233                 LeanbackSettingsFragment callback =
234                         (LeanbackSettingsFragment) getCallbackFragment();
235                 callback.startImmersiveFragment(
236                         RebootConfirmFragment.newInstance(true /* safeMode */));
237                 return true;
238             }
239         }
240         return false;
241     }
242 
243     @Override
onPreferenceTreeClick(Preference preference)244     public boolean onPreferenceTreeClick(Preference preference) {
245         switch (preference.getKey()) {
246             case KEY_FIRMWARE_VERSION:
247                 System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1);
248                 mHits[mHits.length - 1] = SystemClock.uptimeMillis();
249                 if (mHits[0] >= (SystemClock.uptimeMillis() - 500)) {
250                     if (mUm.hasUserRestriction(UserManager.DISALLOW_FUN)) {
251                         Log.d(TAG, "Sorry, no fun for you!");
252                         return false;
253                     }
254 
255                     Intent intent = new Intent(Intent.ACTION_MAIN);
256                     intent.setClassName("android",
257                             com.android.internal.app.PlatLogoActivity.class.getName());
258                     try {
259                         startActivity(intent);
260                     } catch (Exception e) {
261                         Log.e(TAG, "Unable to start activity " + intent.toString());
262                     }
263                 }
264                 break;
265             case KEY_BUILD_NUMBER:
266                 // Don't enable developer options for secondary users.
267                 if (!mUm.isAdminUser())
268                     return true;
269 
270                 if (mUm.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES))
271                     return true;
272 
273                 if (mDevHitCountdown > 0) {
274                     mDevHitCountdown--;
275                     if (mDevHitCountdown == 0) {
276                         Settings.Global.putInt(getActivity().getContentResolver(),
277                                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
278                         if (mDevHitToast != null) {
279                             mDevHitToast.cancel();
280                         }
281                         mDevHitToast = Toast.makeText(getActivity(), R.string.show_dev_on,
282                                 Toast.LENGTH_LONG);
283                         mDevHitToast.show();
284                         // This is good time to index the Developer Options
285 //                    Index.getInstance(
286 //                            getActivity().getApplicationContext()).updateFromClassNameResource(
287 //                            DevelopmentSettings.class.getName(), true, true);
288 
289                     } else if (mDevHitCountdown > 0
290                             && mDevHitCountdown < (TAPS_TO_BE_A_DEVELOPER - 2)) {
291                         if (mDevHitToast != null) {
292                             mDevHitToast.cancel();
293                         }
294                         mDevHitToast = Toast
295                                 .makeText(getActivity(), getResources().getQuantityString(
296                                         R.plurals.show_dev_countdown, mDevHitCountdown,
297                                         mDevHitCountdown),
298                                         Toast.LENGTH_SHORT);
299                         mDevHitToast.show();
300                     }
301                 } else if (mDevHitCountdown < 0) {
302                     if (mDevHitToast != null) {
303                         mDevHitToast.cancel();
304                     }
305                     mDevHitToast = Toast.makeText(getActivity(), R.string.show_dev_already,
306                             Toast.LENGTH_LONG);
307                     mDevHitToast.show();
308                 }
309                 break;
310             case KEY_DEVICE_FEEDBACK:
311                 sendFeedback();
312                 break;
313             case KEY_SYSTEM_UPDATE_SETTINGS:
314                 CarrierConfigManager configManager = (CarrierConfigManager)
315                         getActivity().getSystemService(Context.CARRIER_CONFIG_SERVICE);
316                 PersistableBundle b = configManager.getConfig();
317                 if (b != null &&
318                         b.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) {
319                     ciActionOnSysUpdate(b);
320                 }
321                 break;
322         }
323         return super.onPreferenceTreeClick(preference);
324     }
325 
326     /**
327      * Trigger client initiated action (send intent) on system update
328      */
ciActionOnSysUpdate(PersistableBundle b)329     private void ciActionOnSysUpdate(PersistableBundle b) {
330         String intentStr = b.getString(CarrierConfigManager.
331                 KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING);
332         if (!TextUtils.isEmpty(intentStr)) {
333             String extra = b.getString(CarrierConfigManager.
334                     KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING);
335             String extraVal = b.getString(CarrierConfigManager.
336                     KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING);
337 
338             Intent intent = new Intent(intentStr);
339             if (!TextUtils.isEmpty(extra)) {
340                 intent.putExtra(extra, extraVal);
341             }
342             Log.d(TAG, "ciActionOnSysUpdate: broadcasting intent " + intentStr +
343                     " with extra " + extra + ", " + extraVal);
344             getActivity().getApplicationContext().sendBroadcast(intent);
345         }
346     }
347 
getSystemPropertySummary(String property)348     private String getSystemPropertySummary(String property) {
349         return SystemProperties.get(property,
350                 getResources().getString(R.string.device_info_default));
351     }
352 
isWifiOnly(Context context)353     public static boolean isWifiOnly(Context context) {
354         ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
355                 Context.CONNECTIVITY_SERVICE);
356         return (!cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE));
357     }
358 
sendFeedback()359     private void sendFeedback() {
360         String reporterPackage = DeviceInfoUtils.getFeedbackReporterPackage(getActivity());
361         if (TextUtils.isEmpty(reporterPackage)) {
362             return;
363         }
364         Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
365         intent.setPackage(reporterPackage);
366         startActivityForResult(intent, 0);
367     }
368 }
369