1 /* 2 * Copyright (C) 2014 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.system; 18 19 import com.android.tv.settings.R; 20 import com.android.tv.settings.users.RestrictedProfileDialogFragment; 21 import com.android.tv.settings.util.SettingsHelper; 22 import com.android.tv.settings.dialog.DialogFragment; 23 import com.android.tv.settings.dialog.DialogFragment.Action; 24 25 import android.app.Activity; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.pm.PackageManager; 29 import android.content.pm.ResolveInfo; 30 import android.os.Bundle; 31 import android.os.UserManager; 32 import android.provider.Settings; 33 34 import java.util.ArrayList; 35 import java.util.List; 36 37 /** 38 * Manages app security preferences. TODO: get a better icon from UX TODO: implement Notification 39 * listener settings 40 */ 41 public class SecurityActivity extends Activity implements Action.Listener { 42 43 private static final int CHECK_SET_ID = 1; 44 private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; 45 private static final String ACTION_RESTRICTED_PROFILE = "action_restricted_profile"; 46 private static final String ACTION_SECURITY_UNKNOWN_SOURCES = "action_security_unknown_sources"; 47 private static final String ACTION_SECURITY_UNKNOWN_SOURCES_OFF = 48 "action_security_unknown_sources_off"; 49 private static final String ACTION_SECURITY_VERIFY_APPS = "action_security_verify_apps"; 50 private static final String ACTION_SECURITY_VERIFY_APPS_ON = "action_security_verify_apps_on"; 51 private static final String ACTION_SECURITY_VERIFY_APPS_OFF = "action_security_verify_apps_off"; 52 private static final String ACTION_SECURITY_UNKNOWN_SOURCES_CONFIRM = 53 "action_security_verify_apps_confirm"; 54 private static final String ACTION_SECURITY_UNKNOWN_SOURCES_CONFIRM_OK = 55 "action_security_verify_apps_confirm_ok"; 56 private static final String ACTION_SECURITY_UNKNOWN_SOURCES_CONFIRM_CANCEL = 57 "action_security_verify_apps_confirm_cancel"; 58 59 private static final String TAG_RESTRICTED_PROFILE_SIDECAR_FRAGMENT = 60 "restricted_profile_sidecar"; 61 62 private SettingsHelper mHelper; 63 private boolean mVerifierInstalled; 64 private DialogFragment mMainMenuDialogFragment; 65 66 @Override onCreate(Bundle savedInstanceState)67 protected void onCreate(Bundle savedInstanceState) { 68 mHelper = new SettingsHelper(getApplicationContext()); 69 mVerifierInstalled = isVerifierInstalled(); 70 // Do this after setting up what's needed. 71 super.onCreate(savedInstanceState); 72 mMainMenuDialogFragment = new DialogFragment.Builder() 73 .breadcrumb(getString(R.string.header_category_personal)) 74 .title(getString(R.string.system_security)) 75 .iconResourceId(R.drawable.ic_settings_security) 76 .iconBackgroundColor(getResources().getColor(R.color.icon_background)) 77 .actions(getMainMenuActions()).build(); 78 DialogFragment.add(getFragmentManager(), mMainMenuDialogFragment); 79 } 80 81 @Override onActionClicked(Action action)82 public void onActionClicked(Action action) { 83 if (ACTION_RESTRICTED_PROFILE.equals(action.getKey())) { 84 getFragmentManager().beginTransaction().add(new RestrictedProfileDialogFragment(), 85 TAG_RESTRICTED_PROFILE_SIDECAR_FRAGMENT).commit(); 86 } else if (ACTION_SECURITY_UNKNOWN_SOURCES.equals(action.getKey())) { 87 boolean isNonMarketAppsAllowed = isNonMarketAppsAllowed(); 88 ArrayList<Action> actions = new ArrayList<>(); 89 // Note we only use the check set id if the "on" is checked so if "off" is selected 90 // there is an animation of the check for "off". We don't want the same behavior for 91 // "on" because it has to go through a confirmation sub-dialog. 92 actions.add(new Action.Builder() 93 .key(ACTION_SECURITY_UNKNOWN_SOURCES_CONFIRM) 94 .title(getString(R.string.settings_on)) 95 .checked(isNonMarketAppsAllowed) 96 .checkSetId(isNonMarketAppsAllowed ? CHECK_SET_ID : 0) 97 .build()); 98 actions.add(new Action.Builder() 99 .key(ACTION_SECURITY_UNKNOWN_SOURCES_OFF) 100 .title(getString(R.string.settings_off)) 101 .checked(!isNonMarketAppsAllowed) 102 .checkSetId(CHECK_SET_ID) 103 .build()); 104 105 DialogFragment dialogFragment = new DialogFragment.Builder() 106 .breadcrumb(getString(R.string.system_security)) 107 .title(getString(R.string.security_unknown_sources_title)) 108 .description(getString(R.string.security_unknown_sources_desc)) 109 .actions(actions) 110 .build(); 111 DialogFragment.add(getFragmentManager(), dialogFragment); 112 } else if (ACTION_SECURITY_UNKNOWN_SOURCES_OFF.equals(action.getKey())) { 113 setNonMarketAppsAllowed(false); 114 mMainMenuDialogFragment.setActions(getMainMenuActions()); 115 getFragmentManager().popBackStack(); 116 } else if (ACTION_SECURITY_UNKNOWN_SOURCES_CONFIRM.equals(action.getKey())) { 117 // No point in issuing the confirmation sub-dialog if we're already "on". 118 if (isNonMarketAppsAllowed()) { 119 getFragmentManager().popBackStack(); 120 } else { 121 ArrayList<Action> actions = new ArrayList<>(); 122 actions.add(new Action.Builder() 123 .key(ACTION_SECURITY_UNKNOWN_SOURCES_CONFIRM_OK) 124 .title(getString(R.string.settings_ok)) 125 .build()); 126 actions.add(new Action.Builder() 127 .key(ACTION_SECURITY_UNKNOWN_SOURCES_CONFIRM_CANCEL) 128 .title(getString(R.string.settings_cancel)) 129 .build()); 130 131 DialogFragment dialogFragment = new DialogFragment.Builder() 132 .breadcrumb(getString(R.string.system_security)) 133 .title(getString(R.string.security_unknown_sources_title)) 134 .description(getString(R.string.security_unknown_sources_confirm_desc)) 135 .actions(actions) 136 .build(); 137 DialogFragment.add(getFragmentManager(), dialogFragment); 138 } 139 } else if (ACTION_SECURITY_UNKNOWN_SOURCES_CONFIRM_OK.equals(action.getKey())) { 140 setNonMarketAppsAllowed(true); 141 mMainMenuDialogFragment.setActions(getMainMenuActions()); 142 getFragmentManager().popBackStack(); 143 getFragmentManager().popBackStack(); 144 } else if (ACTION_SECURITY_UNKNOWN_SOURCES_CONFIRM_CANCEL.equals(action.getKey())) { 145 getFragmentManager().popBackStack(); 146 getFragmentManager().popBackStack(); 147 } else if (ACTION_SECURITY_VERIFY_APPS.equals(action.getKey())) { 148 boolean isVerifyAppsEnabled = mVerifierInstalled && isVerifyAppsEnabled(); 149 150 ArrayList<Action> actions = new ArrayList<>(); 151 actions.add(new Action.Builder() 152 .key(ACTION_SECURITY_VERIFY_APPS_ON) 153 .title(getString(R.string.settings_on)) 154 .checked(isVerifyAppsEnabled) 155 .checkSetId(CHECK_SET_ID) 156 .build()); 157 actions.add(new Action.Builder() 158 .key(ACTION_SECURITY_VERIFY_APPS_OFF) 159 .title(getString(R.string.settings_off)) 160 .checked(!isVerifyAppsEnabled) 161 .checkSetId(CHECK_SET_ID) 162 .build()); 163 164 DialogFragment dialogFragment = new DialogFragment.Builder() 165 .breadcrumb(getString(R.string.system_security)) 166 .title(getString(R.string.security_verify_apps_title)) 167 .description(getString(R.string.security_verify_apps_desc)) 168 .actions(actions) 169 .build(); 170 DialogFragment.add(getFragmentManager(), dialogFragment); 171 } else if (ACTION_SECURITY_VERIFY_APPS_ON.equals(action.getKey())) { 172 setVerifyAppsEnabled(true); 173 mMainMenuDialogFragment.setActions(getMainMenuActions()); 174 getFragmentManager().popBackStack(); 175 } else if (ACTION_SECURITY_VERIFY_APPS_OFF.equals(action.getKey())) { 176 setVerifyAppsEnabled(false); 177 mMainMenuDialogFragment.setActions(getMainMenuActions()); 178 getFragmentManager().popBackStack(); 179 } 180 } 181 getMainMenuActions()182 private ArrayList<Action> getMainMenuActions() { 183 boolean isNonMarketAppsAllowed = isNonMarketAppsAllowed(); 184 ArrayList<Action> actions = new ArrayList<>(); 185 actions.add(new Action.Builder() 186 .key(ACTION_SECURITY_UNKNOWN_SOURCES) 187 .title(getString(R.string.security_unknown_sources_title)) 188 .description(mHelper.getStatusStringFromBoolean(isNonMarketAppsAllowed())) 189 .build()); 190 if (showVerifierSetting()) { 191 actions.add(new Action.Builder() 192 .key(ACTION_SECURITY_VERIFY_APPS) 193 .title(getString(R.string.security_verify_apps_title)) 194 .description(mHelper.getStatusStringFromBoolean(isVerifyAppsEnabled() 195 && mVerifierInstalled)) 196 .enabled(mVerifierInstalled) 197 .build()); 198 } 199 actions.add(new Action.Builder().key(ACTION_RESTRICTED_PROFILE) 200 .title(getString(R.string.launcher_restricted_profile_app_name)) 201 .description(RestrictedProfileDialogFragment.getActionDescription(this)) 202 .build()); 203 return actions; 204 } 205 isNonMarketAppsAllowed()206 private boolean isNonMarketAppsAllowed() { 207 return Settings.Global.getInt(getContentResolver(), 208 Settings.Global.INSTALL_NON_MARKET_APPS, 0) > 0; 209 } 210 setNonMarketAppsAllowed(boolean enabled)211 private void setNonMarketAppsAllowed(boolean enabled) { 212 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); 213 if (um.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)) { 214 return; 215 } 216 // Change the system setting 217 Settings.Global.putInt(getContentResolver(), Settings.Global.INSTALL_NON_MARKET_APPS, 218 enabled ? 1 : 0); 219 } 220 isVerifyAppsEnabled()221 private boolean isVerifyAppsEnabled() { 222 return Settings.Global.getInt(getContentResolver(), 223 Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) > 0; 224 } 225 setVerifyAppsEnabled(boolean enable)226 private void setVerifyAppsEnabled(boolean enable) { 227 Settings.Global.putInt(getContentResolver(), Settings.Global.PACKAGE_VERIFIER_ENABLE, 228 enable ? 1 : 0); 229 } 230 isVerifierInstalled()231 private boolean isVerifierInstalled() { 232 final PackageManager pm = getPackageManager(); 233 final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); 234 verification.setType(PACKAGE_MIME_TYPE); 235 verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 236 final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(verification, 0); 237 return (receivers.size() > 0) ? true : false; 238 } 239 showVerifierSetting()240 private boolean showVerifierSetting() { 241 return Settings.Global.getInt(getContentResolver(), 242 Settings.Global.PACKAGE_VERIFIER_SETTING_VISIBLE, 1) > 0; 243 } 244 245 } 246