1 /* 2 * Copyright (C) 2020 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.emergency.action; 18 19 import android.app.Activity; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.res.Configuration; 23 import android.os.Bundle; 24 import android.os.CountDownTimer; 25 import android.support.v4.app.Fragment; 26 import android.telecom.TelecomManager; 27 import android.util.DisplayMetrics; 28 import android.util.Log; 29 import android.view.LayoutInflater; 30 import android.view.View; 31 import android.view.ViewGroup; 32 import android.widget.TextView; 33 34 import androidx.annotation.NonNull; 35 import androidx.annotation.Nullable; 36 37 import com.android.emergency.R; 38 import com.android.emergency.action.broadcast.EmergencyActionBroadcastReceiver; 39 import com.android.emergency.action.sensoryfeedback.EmergencyActionAlarmHelper; 40 import com.android.emergency.action.service.EmergencyActionForegroundService; 41 import com.android.emergency.widgets.countdown.CountDownAnimationView; 42 import com.android.emergency.widgets.slider.OnSlideCompleteListener; 43 import com.android.emergency.widgets.slider.SliderView; 44 import com.android.settingslib.emergencynumber.EmergencyNumberUtils; 45 46 import java.time.Duration; 47 48 public class EmergencyActionFragment extends Fragment implements OnSlideCompleteListener { 49 50 private static final String TAG = "EmergencyActionFrag"; 51 private static final String STATE_MILLIS_LEFT = "STATE_MILLIS_LEFT"; 52 53 private EmergencyActionAlarmHelper mEmergencyActionAlarmHelper; 54 private TelecomManager mTelecomManager; 55 private CountDownTimer mCountDownTimer; 56 private EmergencyNumberUtils mEmergencyNumberUtils; 57 private long mCountDownMillisLeft; 58 59 private boolean mCountdownCancelled; 60 private boolean mCountdownFinished; 61 62 @Override onAttach(Context context)63 public void onAttach(Context context) { 64 super.onAttach(context); 65 EmergencyActionForegroundService.stopService(context); 66 mEmergencyActionAlarmHelper = new EmergencyActionAlarmHelper(context); 67 mEmergencyNumberUtils = new EmergencyNumberUtils(context); 68 mTelecomManager = context.getSystemService(TelecomManager.class); 69 } 70 71 @Override onCreateView(@onNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)72 public View onCreateView(@NonNull LayoutInflater inflater, 73 @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 74 75 // Ignore the larger font scale if users set it in general system settings since we already 76 // have relatively large font size on this page, and we need to display all content on one 77 // page without scrolling. 78 Configuration configuration = getResources().getConfiguration(); 79 if (configuration.fontScale > 1) { 80 configuration.fontScale = (float) 1; 81 82 DisplayMetrics metrics = new DisplayMetrics(); 83 metrics.scaledDensity = configuration.fontScale * metrics.density; 84 configuration.densityDpi = (int) getResources().getDisplayMetrics().xdpi; 85 } 86 87 View view = inflater.cloneInContext(getContext().createConfigurationContext(configuration)) 88 .inflate(R.layout.emergency_action_fragment, container, false); 89 90 TextView subtitleView = view.findViewById(R.id.subtitle); 91 subtitleView.setText(getString(R.string.emergency_action_subtitle, 92 mEmergencyNumberUtils.getPoliceNumber())); 93 94 SliderView cancelButton = view.findViewById(R.id.btn_cancel); 95 cancelButton.setSlideCompleteListener(this); 96 97 if (savedInstanceState != null) { 98 mCountDownMillisLeft = savedInstanceState.getLong(STATE_MILLIS_LEFT); 99 } else { 100 Activity activity = getActivity(); 101 Intent intent = null; 102 if (activity != null) { 103 intent = activity.getIntent(); 104 } 105 if (intent != null) { 106 mCountDownMillisLeft = intent.getLongExtra(STATE_MILLIS_LEFT, 107 getResources().getInteger(R.integer.emergency_action_count_down_millis)); 108 } else { 109 mCountDownMillisLeft = 110 getResources().getInteger(R.integer.emergency_action_count_down_millis); 111 } 112 } 113 114 return view; 115 } 116 117 @Override onStart()118 public void onStart() { 119 super.onStart(); 120 startTimer(); 121 mEmergencyActionAlarmHelper.playWarningSound(); 122 } 123 124 @Override onSaveInstanceState(Bundle outState)125 public void onSaveInstanceState(Bundle outState) { 126 super.onSaveInstanceState(outState); 127 outState.putLong(STATE_MILLIS_LEFT, mCountDownMillisLeft); 128 } 129 130 @Override onStop()131 public void onStop() { 132 super.onStop(); 133 134 if (mCountDownTimer != null) { 135 CountDownAnimationView countDownAnimationView = 136 getView().findViewById(R.id.count_down_view); 137 countDownAnimationView.stop(); 138 mCountDownTimer.cancel(); 139 } 140 141 mEmergencyActionAlarmHelper.stopWarningSound(); 142 if (!mCountdownCancelled && !mCountdownFinished) { 143 Log.d(TAG, 144 "Emergency countdown UI dismissed without being cancelled/finished, " 145 + "continuing countdown in background"); 146 147 Context context = getContext(); 148 context.startService( 149 EmergencyActionForegroundService.newStartCountdownIntent( 150 context, 151 mCountDownMillisLeft, 152 mEmergencyActionAlarmHelper.getUserSetAlarmVolume())); 153 } 154 } 155 156 @Override onSlideComplete()157 public void onSlideComplete() { 158 mCountdownCancelled = true; 159 EmergencyActionForegroundService.stopService(getActivity()); 160 getActivity().finish(); 161 } 162 startTimer()163 private void startTimer() { 164 CountDownAnimationView countDownAnimationView = 165 getView().findViewById(R.id.count_down_view); 166 167 if (mCountDownTimer != null) { 168 countDownAnimationView.stop(); 169 mCountDownTimer.cancel(); 170 } 171 172 mCountDownTimer = 173 new CountDownTimer( 174 mCountDownMillisLeft, 175 getResources().getInteger(R.integer.emergency_action_count_down_interval)) { 176 @Override 177 public void onTick(long millisUntilFinished) { 178 CountDownAnimationView countDownAnimationView = 179 getView().findViewById(R.id.count_down_view); 180 if (countDownAnimationView != null) { 181 countDownAnimationView.setCountDownLeft( 182 Duration.ofMillis(millisUntilFinished)); 183 } 184 185 mCountDownMillisLeft = millisUntilFinished; 186 } 187 188 @Override 189 public void onFinish() { 190 mCountdownFinished = true; 191 Intent broadcast = 192 EmergencyActionBroadcastReceiver.newCallEmergencyIntent( 193 getContext()); 194 Activity activity = getActivity(); 195 activity.sendBroadcast(broadcast); 196 activity.finish(); 197 } 198 }; 199 200 mCountDownTimer.start(); 201 202 countDownAnimationView.start(Duration.ofMillis(mCountDownMillisLeft)); 203 countDownAnimationView.showCountDown(); 204 } 205 } 206