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.messaging.util; 18 19 import android.app.Activity; 20 import android.app.Fragment; 21 import android.content.ActivityNotFoundException; 22 import android.content.Intent; 23 import android.view.View; 24 25 import com.android.messaging.R; 26 import com.android.messaging.ui.SnackBar; 27 import com.android.messaging.ui.UIIntents; 28 29 public class ChangeDefaultSmsAppHelper { 30 private Runnable mRunAfterMadeDefault; 31 private ChangeSmsAppSettingRunnable mChangeSmsAppSettingRunnable; 32 33 private static final int REQUEST_SET_DEFAULT_SMS_APP = 1; 34 35 /** 36 * When there's some condition that prevents an operation, such as sending a message, 37 * call warnOfMissingActionConditions to put up a toast and allow the user to repair 38 * that condition. 39 * @param sending - true if we're called during a sending operation 40 * @param runAfterMadeDefault - a runnable to run after the user responds 41 * positively to the condition prompt and resolves the condition. It is 42 * preferable to specify the value in {@link #handleChangeDefaultSmsResult} 43 * as that handles the case where the process gets restarted. 44 * If null, the user will be shown a generic toast message. 45 * @param composeView - compose view that may have the keyboard opened and focused 46 * @param rootView - if non-null, use this to attach a snackBar 47 * @param activity - calling activity 48 * @param fragment - calling fragment, may be null if called directly from an activity 49 */ warnOfMissingActionConditions(final boolean sending, final Runnable runAfterMadeDefault, final View composeView, final View rootView, final Activity activity, final Fragment fragment)50 public void warnOfMissingActionConditions(final boolean sending, 51 final Runnable runAfterMadeDefault, 52 final View composeView, final View rootView, 53 final Activity activity, final Fragment fragment) { 54 final PhoneUtils phoneUtils = PhoneUtils.getDefault(); 55 final boolean isSmsCapable = phoneUtils.isSmsCapable(); 56 final boolean hasPreferredSmsSim = phoneUtils.getHasPreferredSmsSim(); 57 final boolean isDefaultSmsApp = phoneUtils.isDefaultSmsApp(); 58 59 // Supports SMS? 60 if (!isSmsCapable) { 61 UiUtils.showToast(R.string.sms_disabled); 62 63 // Has a preferred sim? 64 } else if (!hasPreferredSmsSim) { 65 UiUtils.showToast(R.string.no_preferred_sim_selected); 66 67 // Is the default sms app? 68 } else if (!isDefaultSmsApp) { 69 mChangeSmsAppSettingRunnable = new ChangeSmsAppSettingRunnable(activity, fragment); 70 promptToChangeDefaultSmsApp(sending, runAfterMadeDefault, 71 composeView, rootView, activity); 72 } 73 74 LogUtil.w(LogUtil.BUGLE_TAG, "Unsatisfied action condition: " 75 + "isSmsCapable=" + isSmsCapable + ", " 76 + "hasPreferredSmsSim=" + hasPreferredSmsSim + ", " 77 + "isDefaultSmsApp=" + isDefaultSmsApp); 78 } 79 promptToChangeDefaultSmsApp(final boolean sending, final Runnable runAfterMadeDefault, final View composeView, final View rootView, final Activity activity)80 private void promptToChangeDefaultSmsApp(final boolean sending, 81 final Runnable runAfterMadeDefault, 82 final View composeView, final View rootView, 83 final Activity activity) { 84 if (composeView != null) { 85 // Avoid bug in system which puts soft keyboard over dialog after orientation change 86 ImeUtil.hideSoftInput(activity, composeView); 87 } 88 mRunAfterMadeDefault = runAfterMadeDefault; 89 90 if (rootView == null) { 91 // Immediately open the system "Change default SMS app?" dialog setting. 92 mChangeSmsAppSettingRunnable.run(); 93 } else { 94 UiUtils.showSnackBarWithCustomAction(activity, 95 rootView, 96 activity.getString(sending ? R.string.requires_default_sms_app_to_send : 97 R.string.requires_default_sms_app), 98 SnackBar.Action.createCustomAction(mChangeSmsAppSettingRunnable, 99 activity.getString(R.string.requires_default_sms_change_button)), 100 null /* interactions */, 101 SnackBar.Placement.above(composeView)); 102 } 103 } 104 105 private class ChangeSmsAppSettingRunnable implements Runnable { 106 private final Activity mActivity; 107 private final Fragment mFragment; 108 ChangeSmsAppSettingRunnable(final Activity activity, final Fragment fragment)109 public ChangeSmsAppSettingRunnable(final Activity activity, final Fragment fragment) { 110 mActivity = activity; 111 mFragment = fragment; 112 } 113 114 @Override run()115 public void run() { 116 try { 117 final Intent intent = UIIntents.get().getChangeDefaultSmsAppIntent(mActivity); 118 if (mFragment != null) { 119 mFragment.startActivityForResult(intent, REQUEST_SET_DEFAULT_SMS_APP); 120 } else { 121 mActivity.startActivityForResult(intent, REQUEST_SET_DEFAULT_SMS_APP); 122 } 123 } catch (final ActivityNotFoundException ex) { 124 // We shouldn't get here, but the monkey on JB MR0 can trigger it. 125 LogUtil.w(LogUtil.BUGLE_TAG, "Couldn't find activity:", ex); 126 UiUtils.showToastAtBottom(R.string.activity_not_found_message); 127 } 128 } 129 } 130 handleChangeDefaultSmsResult( final int requestCode, final int resultCode, Runnable runAfterMadeDefault)131 public void handleChangeDefaultSmsResult( 132 final int requestCode, 133 final int resultCode, 134 Runnable runAfterMadeDefault) { 135 Assert.isTrue(mRunAfterMadeDefault == null || runAfterMadeDefault == null); 136 if (runAfterMadeDefault == null) { 137 runAfterMadeDefault = mRunAfterMadeDefault; 138 } 139 140 if (requestCode == REQUEST_SET_DEFAULT_SMS_APP) { 141 if (resultCode == Activity.RESULT_OK) { 142 // mRunAfterMadeDefault can be null if it was set only in 143 // promptToChangeDefaultSmsApp, and the process subsequently restarted when the 144 // user momentarily switched to another app. In that case, we'll simply show a 145 // generic toast since we do not know what the runnable was supposed to do. 146 if (runAfterMadeDefault != null) { 147 runAfterMadeDefault.run(); 148 } else { 149 UiUtils.showToast(R.string.toast_after_setting_default_sms_app); 150 } 151 } 152 mRunAfterMadeDefault = null; // don't want to accidentally run it again 153 } 154 } 155 } 156 157 158