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