1 /* 2 * Copyright (C) 2016 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 package com.android.settings.network; 17 18 import static android.provider.SettingsSlicesContract.KEY_AIRPLANE_MODE; 19 20 import static com.android.settings.network.SatelliteWarningDialogActivity.EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG; 21 import static com.android.settings.network.SatelliteWarningDialogActivity.TYPE_IS_AIRPLANE_MODE; 22 23 import android.app.Activity; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.pm.PackageManager; 28 import android.net.Uri; 29 import android.provider.SettingsSlicesContract; 30 import android.telephony.TelephonyManager; 31 import android.util.Log; 32 33 import androidx.annotation.VisibleForTesting; 34 import androidx.fragment.app.Fragment; 35 import androidx.preference.Preference; 36 import androidx.preference.PreferenceScreen; 37 import androidx.preference.TwoStatePreference; 38 39 import com.android.settings.AirplaneModeEnabler; 40 import com.android.settings.R; 41 import com.android.settings.Utils; 42 import com.android.settings.core.TogglePreferenceController; 43 import com.android.settingslib.core.lifecycle.LifecycleObserver; 44 import com.android.settingslib.core.lifecycle.events.OnDestroy; 45 import com.android.settingslib.core.lifecycle.events.OnResume; 46 import com.android.settingslib.core.lifecycle.events.OnStart; 47 import com.android.settingslib.core.lifecycle.events.OnStop; 48 49 import java.util.concurrent.ExecutionException; 50 import java.util.concurrent.Executors; 51 import java.util.concurrent.TimeUnit; 52 import java.util.concurrent.TimeoutException; 53 import java.util.concurrent.atomic.AtomicBoolean; 54 55 public class AirplaneModePreferenceController extends TogglePreferenceController 56 implements LifecycleObserver, OnStart, OnResume, OnStop, OnDestroy, 57 AirplaneModeEnabler.OnAirplaneModeChangedListener { 58 private static final String TAG = AirplaneModePreferenceController.class.getSimpleName(); 59 public static final int REQUEST_CODE_EXIT_ECM = 1; 60 61 /** 62 * Uri for Airplane mode Slice. 63 */ 64 public static final Uri SLICE_URI = new Uri.Builder() 65 .scheme(ContentResolver.SCHEME_CONTENT) 66 .authority(SettingsSlicesContract.AUTHORITY) 67 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 68 .appendPath(SettingsSlicesContract.KEY_AIRPLANE_MODE) 69 .build(); 70 71 private Fragment mFragment; 72 private AirplaneModeEnabler mAirplaneModeEnabler; 73 private TwoStatePreference mAirplaneModePreference; 74 private SatelliteRepository mSatelliteRepository; 75 @VisibleForTesting 76 AtomicBoolean mIsSatelliteOn = new AtomicBoolean(false); 77 AirplaneModePreferenceController(Context context, String key)78 public AirplaneModePreferenceController(Context context, String key) { 79 super(context, key); 80 if (isAvailable(mContext)) { 81 mAirplaneModeEnabler = new AirplaneModeEnabler(mContext, this); 82 mSatelliteRepository = new SatelliteRepository(mContext); 83 } 84 } 85 setFragment(Fragment hostFragment)86 public void setFragment(Fragment hostFragment) { 87 mFragment = hostFragment; 88 } 89 90 @VisibleForTesting setAirplaneModeEnabler(AirplaneModeEnabler airplaneModeEnabler)91 void setAirplaneModeEnabler(AirplaneModeEnabler airplaneModeEnabler) { 92 mAirplaneModeEnabler = airplaneModeEnabler; 93 } 94 95 @Override handlePreferenceTreeClick(Preference preference)96 public boolean handlePreferenceTreeClick(Preference preference) { 97 if (KEY_AIRPLANE_MODE.equals(preference.getKey()) && isAvailable()) { 98 // In ECM mode launch ECM app dialog 99 if (mAirplaneModeEnabler.isInEcmMode()) { 100 if (mFragment != null) { 101 mFragment.startActivityForResult( 102 new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null) 103 .setPackage(Utils.PHONE_PACKAGE_NAME), 104 REQUEST_CODE_EXIT_ECM); 105 } 106 return true; 107 } 108 109 if (mIsSatelliteOn.get()) { 110 mContext.startActivity( 111 new Intent(mContext, SatelliteWarningDialogActivity.class) 112 .putExtra( 113 EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, 114 TYPE_IS_AIRPLANE_MODE) 115 ); 116 return true; 117 } 118 } 119 return false; 120 } 121 122 @Override getSliceUri()123 public Uri getSliceUri() { 124 return SLICE_URI; 125 } 126 127 @Override displayPreference(PreferenceScreen screen)128 public void displayPreference(PreferenceScreen screen) { 129 super.displayPreference(screen); 130 mAirplaneModePreference = screen.findPreference(getPreferenceKey()); 131 } 132 isAvailable(Context context)133 public static boolean isAvailable(Context context) { 134 return context.getResources().getBoolean(R.bool.config_show_toggle_airplane) 135 && !context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); 136 } 137 138 @Override isPublicSlice()139 public boolean isPublicSlice() { 140 return true; 141 } 142 143 @Override 144 @AvailabilityStatus getAvailabilityStatus()145 public int getAvailabilityStatus() { 146 return isAvailable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE; 147 } 148 149 @Override getSliceHighlightMenuRes()150 public int getSliceHighlightMenuRes() { 151 return R.string.menu_key_network; 152 } 153 154 @Override onStart()155 public void onStart() { 156 if (isAvailable()) { 157 mAirplaneModeEnabler.start(); 158 } 159 } 160 161 @Override onResume()162 public void onResume() { 163 try { 164 mIsSatelliteOn.set( 165 mSatelliteRepository.requestIsEnabled(Executors.newSingleThreadExecutor()) 166 .get(2000, TimeUnit.MILLISECONDS)); 167 } catch (ExecutionException | TimeoutException | InterruptedException e) { 168 Log.e(TAG, "Error to get satellite status : " + e); 169 } 170 } 171 172 @Override onStop()173 public void onStop() { 174 if (isAvailable()) { 175 mAirplaneModeEnabler.stop(); 176 } 177 } 178 179 @Override onDestroy()180 public void onDestroy() { 181 if (isAvailable()) { 182 mAirplaneModeEnabler.close(); 183 } 184 } 185 186 onActivityResult(int requestCode, int resultCode, Intent data)187 public void onActivityResult(int requestCode, int resultCode, Intent data) { 188 if (requestCode == REQUEST_CODE_EXIT_ECM && isAvailable()) { 189 final boolean isChoiceYes = (resultCode == Activity.RESULT_OK); 190 // Set Airplane mode based on the return value and checkbox state 191 mAirplaneModeEnabler.setAirplaneModeInECM(isChoiceYes, 192 mAirplaneModePreference.isChecked()); 193 } 194 } 195 196 @Override isChecked()197 public boolean isChecked() { 198 return isAvailable() && mAirplaneModeEnabler.isAirplaneModeOn(); 199 } 200 201 @Override setChecked(boolean isChecked)202 public boolean setChecked(boolean isChecked) { 203 if (isChecked() == isChecked || mIsSatelliteOn.get()) { 204 return false; 205 } 206 if (isAvailable()) { 207 mAirplaneModeEnabler.setAirplaneMode(isChecked); 208 } 209 return true; 210 } 211 212 @Override onAirplaneModeChanged(boolean isAirplaneModeOn)213 public void onAirplaneModeChanged(boolean isAirplaneModeOn) { 214 if (mAirplaneModePreference != null) { 215 mAirplaneModePreference.setChecked(isAirplaneModeOn); 216 } 217 } 218 } 219