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
17package com.android.omadm.service;
18
19import android.app.Activity;
20import android.app.AlertDialog;
21import android.app.KeyguardManager;
22import android.app.ProgressDialog;
23import android.content.BroadcastReceiver;
24import android.content.Context;
25import android.content.DialogInterface;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.os.Bundle;
29import android.os.Handler;
30import android.os.PowerManager;
31import android.text.InputFilter;
32import android.text.InputType;
33import android.util.Log;
34import android.view.KeyEvent;
35import android.view.LayoutInflater;
36import android.view.View;
37import android.widget.EditText;
38
39import java.util.Arrays;
40
41public class DMAlertActivity extends Activity {
42    private static final String TAG = "DMAlertActivity";
43    private static final boolean DBG = DMClientService.DBG;
44
45    private static final int DISPLAY_ALERT_DIALOG = 1;
46
47    private static final int CONFIRM_ALERT_DIALOG = 2;
48
49    private static final int TEXTINPUT_ALERT_DIALOG = 3;
50
51    private static final int SINGLECHOICE_ALERT_DIALOG = 4;
52
53    private static final int MULTICHOICE_ALERT_DIALOG = 5;
54
55    private static final int SHOW_PROGRESS_ALERT_DIALOG = 6;
56
57    private static final int HIDE_PROGRESS_ALERT_DIALOG = 7;
58
59    private static final int CANCEL_ALERT_DIALOG = 8;
60
61    private static AlertDialog mDialog;
62
63    private Runnable mDialogTimeout;
64
65    private KeyReceiver mKeyReceiver;
66
67    private static PowerManager.WakeLock wl;
68
69    private KeyguardManager.KeyguardLock mKeyguardLock;
70
71    private int mType;
72
73    private String mMessage;
74
75    private String mTitle;
76
77    private int mIcon;
78
79    private int mTimeout;
80
81    private int mMaxLength;
82
83    private EditText mInputBox;
84
85    private int mInputType;
86
87    private String[] mChoices;
88
89    private int mCheckedItem;
90
91    private boolean[] mCheckedItems;
92
93    private int mResultCode; // == DMAlert.DM_SERVICE_ALERT_RESP_SUCCESS (0)
94
95    private String mResultData;
96
97    private Handler mHandler;
98
99    @Override
100    public void onCreate(Bundle savedInstanceState) {
101        super.onCreate(savedInstanceState);
102        if (DBG) {
103            logd("onCreate");
104        }
105
106        final Intent intent = getIntent();
107        mMessage = intent.getStringExtra("Message");
108        mTitle = intent.getStringExtra("Title");
109        mIcon = intent.getIntExtra("Icon", -1);
110        mTimeout = intent.getIntExtra("Timeout", 0);
111        if (DBG) {
112            logd("mMessage: " + mMessage);
113        }
114        if (DBG) {
115            logd("mTitle: " + mTitle);
116        }
117        if (DBG) {
118            logd("mIcon: " + mIcon);
119        }
120        if (DBG) {
121            logd("mTimeout: " + mTimeout);
122        }
123
124        String action = intent.getAction();
125        if (action.equals(DMIntent.SHOW_DISPLAY_ALERT_DLG)) {
126            mType = DISPLAY_ALERT_DIALOG;
127        } else if (action.equals(DMIntent.SHOW_CONFIRM_ALERT_DLG)) {
128            mType = CONFIRM_ALERT_DIALOG;
129        } else if (action.equals(DMIntent.SHOW_TEXTINPUT_ALERT_DLG)) {
130            mType = TEXTINPUT_ALERT_DIALOG;
131            mMaxLength = intent.getIntExtra("MaxLength", 80);
132            if (DBG) {
133                logd("mMaxLength: " + mMaxLength);
134            }
135            mInputType = intent.getIntExtra("InputType", InputType.TYPE_CLASS_TEXT);
136            if (DBG) {
137                logd("mInputType: " + mInputType);
138            }
139            mResultData = intent.getStringExtra("DefaultText");
140            if (DBG) {
141                logd("mResultData: " + mResultData);
142            }
143        } else if (action.equals(DMIntent.SHOW_SINGLECHOICE_ALERT_DLG)) {
144            mType = SINGLECHOICE_ALERT_DIALOG;
145            mChoices = intent.getStringArrayExtra("Choices");
146            mCheckedItem = intent.getIntExtra("CheckedItem", -1);
147            for (int i = 0; i < mChoices.length; i++) {
148                if (DMClientService.DBG) {
149                    logd("mChoices: " + i + ": " + mChoices[i]);
150                }
151            }
152            if (DMClientService.DBG) {
153                logd("mCheckedItem: " + mCheckedItem);
154            }
155        } else if (action.equals(DMIntent.SHOW_MULTICHOICE_ALERT_DLG)) {
156            mType = MULTICHOICE_ALERT_DIALOG;
157            mChoices = intent.getStringArrayExtra("Choices");
158            for (int i = 0; i < mChoices.length; i++) {
159                if (DMClientService.DBG) {
160                    logd("mChoices " + i + ": " + mChoices[i]);
161                }
162            }
163            mCheckedItems = intent.getBooleanArrayExtra("CheckedItems");
164            for (int i = 0; i < mCheckedItems.length; i++) {
165                if (DMClientService.DBG) {
166                    logd("CheckedItems " + i + ": " + mCheckedItems[i]);
167                }
168            }
169        } else if (action.equals(DMIntent.SHOW_PROGRESS_ALERT_DLG)) {
170            mType = SHOW_PROGRESS_ALERT_DIALOG;
171        } else if (action.equals(DMIntent.HIDE_PROGRESS_ALERT_DLG)) {
172            mType = HIDE_PROGRESS_ALERT_DIALOG;
173            onFinish();
174            if (DMClientService.DBG) {
175                logd("HIDE_PROGRESS_ALERT_DLG");
176            }
177            return;
178        } else if (action.equals(DMIntent.CANCEL_ALERT_DLG)) {
179            mType = CANCEL_ALERT_DIALOG;
180            onFinish();
181            if (DMClientService.DBG) {
182                logd("CANCEL_ALERT_DIALOG");
183            }
184            return;
185        } else {
186            if (DMClientService.DBG) {
187                logd("TODO: new dialog type support!");
188            }
189            return;
190        }
191
192        if (null != mDialog) {
193            if (DMClientService.DBG) {
194                logd("Cancel previous dialog!");
195            }
196            mDialog.dismiss();
197            mDialog = null;
198        }
199
200        setVisible(false);
201
202        showDialog(mType);
203
204        mKeyReceiver = new KeyReceiver();
205        IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
206        IntentFilter searchkeyFilter = new IntentFilter(Intent.ACTION_SEARCH);
207        IntentFilter searchkeyFilterLongPress = new IntentFilter(Intent.ACTION_SEARCH_LONG_PRESS);
208        registerReceiver(mKeyReceiver, searchkeyFilter);
209        registerReceiver(mKeyReceiver, searchkeyFilterLongPress);
210        registerReceiver(mKeyReceiver, filter);
211
212        if (mTimeout <= 0 || mTimeout > 300) {
213            if (DMClientService.DBG) {
214                logd("Forcing the default and max Timeout to 5mins");
215            }
216            mTimeout = 300; //forcing the default and max timeout to 5mins
217            //return;
218        }
219
220        mHandler = new Handler();
221        mDialogTimeout = new Runnable() {
222            @Override
223            public void run() {
224                mResultCode = DMAlert.DM_SERVICE_ALERT_RESP_TIMEOUT;
225                onFinish();
226                if (DMClientService.DBG) {
227                    logd("DMAlert.DM_SERVICE_ALERT_RESP_TIMEOUT");
228                }
229            }
230        };
231        mHandler.postDelayed(mDialogTimeout, mTimeout * 1000);
232    }
233
234    private final class KeyReceiver extends BroadcastReceiver {
235
236        KeyReceiver() {
237        }
238
239        @Override
240        public void onReceive(Context arg0, Intent arg1) {
241            Log.i(TAG, "receive the broadcast " + arg1.getAction());
242            mResultCode = DMAlert.DM_SERVICE_ALERT_RESP_CANCEL;
243            onFinish();
244        }
245    }
246
247    @Override
248    protected AlertDialog onCreateDialog(int id) {
249        if (DMClientService.DBG) {
250            logd("Dialog Type: " + id);
251        }
252        getKeyGuardAndWakeLock();
253
254        switch (id) {
255            case DISPLAY_ALERT_DIALOG:
256                mDialog = new AlertDialog.Builder(this)
257                        .setTitle(mTitle)
258                        .setMessage(mMessage)
259                        .setCancelable(true)
260                        .setView(null)
261                        .create();
262                break;
263            case CONFIRM_ALERT_DIALOG:
264                mDialog = new AlertDialog.Builder(this)
265                        .setTitle(mTitle)
266                        .setMessage(mMessage)
267                        .setPositiveButton(
268                                getResources().getString(R.string.DM_SERVICE_ALERT_BUTTON_YES),
269                                mKeyYesClickListener)
270                        .setNegativeButton(
271                                getResources().getString(R.string.DM_SERVICE_ALERT_BUTTON_NO),
272                                mKeyNoClickListener)
273                        .setCancelable(true)
274                        .create();
275                break;
276            case TEXTINPUT_ALERT_DIALOG:
277                View view = LayoutInflater.from(this).inflate(R.layout.textinput_dialog, null);
278                mInputBox = (EditText) view.findViewById(R.id.textinput_content);
279                mInputBox.requestFocus();
280                mInputBox.setText(mResultData);
281                mInputBox.setInputType(mInputType);
282                InputFilter[] f = new InputFilter[1];
283                f[0] = new InputFilter.LengthFilter(mMaxLength);
284                mInputBox.setFilters(f);
285
286                mDialog = new AlertDialog.Builder(this)
287                        .setTitle(mTitle)
288                        .setMessage(mMessage)
289                        .setView(view)
290                        .setPositiveButton(
291                                getResources().getString(R.string.DM_SERVICE_ALERT_BUTTON_YES),
292                                mKeyYesClickListener)
293                        .setNegativeButton(
294                                getResources().getString(R.string.DM_SERVICE_ALERT_BUTTON_NO),
295                                mKeyNoClickListener)
296                        .create();
297                break;
298            case SINGLECHOICE_ALERT_DIALOG:
299                mDialog = new AlertDialog.Builder(this)
300                        .setTitle(mMessage)
301                        .setSingleChoiceItems(mChoices, mCheckedItem, mSingleChoiceClickListener)
302                        .setPositiveButton(
303                                getResources().getString(R.string.DM_SERVICE_ALERT_BUTTON_YES),
304                                mKeyYesClickListener)
305                        .setNegativeButton(
306                                getResources().getString(R.string.DM_SERVICE_ALERT_BUTTON_NO),
307                                mKeyNoClickListener)
308                        .setCancelable(true)
309                        .create();
310                break;
311            case MULTICHOICE_ALERT_DIALOG:
312                mDialog = new AlertDialog.Builder(this)
313                        .setTitle(mMessage)
314                        .setMultiChoiceItems(mChoices, mCheckedItems, mMultiChoiceClickListener)
315                        .setPositiveButton(
316                                getResources().getString(R.string.DM_SERVICE_ALERT_BUTTON_YES),
317                                mKeyYesClickListener)
318                        .setNegativeButton(
319                                getResources().getString(R.string.DM_SERVICE_ALERT_BUTTON_NO),
320                                mKeyNoClickListener)
321                        .setCancelable(true)
322                        .create();
323                break;
324
325            case SHOW_PROGRESS_ALERT_DIALOG:
326                mDialog = new ProgressDialog(this);
327                mDialog.setTitle(mTitle);
328                mDialog.setMessage(mMessage);
329                mDialog.setCancelable(true);
330                if (DMClientService.DBG) {
331                    logd("SHOW_PROGRESS_ALERT_DIALOG");
332                }
333                break;
334
335            default:
336                Log.i(TAG, "Unknown dialog type: " + id);
337                return null;
338        }
339
340        if (-1 != mIcon) {
341            mDialog.setIcon(mIcon);
342        }
343
344        mDialog.setOnCancelListener(mOnCancelListener);
345        return mDialog;
346    }
347
348    private void getKeyGuardAndWakeLock() {
349        logd("Inside getKeyGuardAndWakeLock");
350        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
351        wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
352                PowerManager.ACQUIRE_CAUSES_WAKEUP |
353                PowerManager.ON_AFTER_RELEASE, TAG);
354        logd("Acquiring the wakelock");
355        wl.acquire();
356
357        KeyguardManager keyguardManager = (KeyguardManager) getSystemService(
358                Context.KEYGUARD_SERVICE);
359        mKeyguardLock = keyguardManager.newKeyguardLock(TAG);
360        logd("Disabling the KeyGuard");
361        mKeyguardLock.disableKeyguard();
362    }
363
364    @Override
365    public boolean onKeyDown(int keyCode, KeyEvent event) {
366        if (DMClientService.DBG) {
367            logd("onKeyDown - keyCode: " + keyCode + " DialogType: " + mType);
368        }
369        if (keyCode == KeyEvent.KEYCODE_BACK) {
370            onFinish();
371            return true;
372        }
373        return false;
374    }
375
376    @Override
377    public void onDestroy() {
378        if (DMClientService.DBG) {
379            logd("onDestroy - DialogType: " + mType);
380        }
381        if (mKeyReceiver != null) {
382            unregisterReceiver(mKeyReceiver);
383        }
384        releaseKeyGuardAndWakeLock();
385        super.onDestroy();
386    }
387
388    private void onFinish() {
389        if (DMClientService.DBG) {
390            logd("OnFinish: Dialog - " + mType);
391        }
392
393        if (mTimeout > 0) {
394            mHandler.removeCallbacks(mDialogTimeout);
395        }
396
397        if (null != mDialog) {
398            mDialog.dismiss();
399        }
400
401        mDialog = null;
402
403        if (mType == DISPLAY_ALERT_DIALOG ||
404                mType == SHOW_PROGRESS_ALERT_DIALOG ||
405                mType == HIDE_PROGRESS_ALERT_DIALOG ||
406                mType == CANCEL_ALERT_DIALOG) {
407            finish();
408            return;
409        }
410
411        Intent i = new Intent(DMIntent.DM_ALERT_DLG_CLOSED);
412
413        i.putExtra("ResultCode", mResultCode);
414        if (DMClientService.DBG) {
415            logd("onFinish - ResultCode: " + mResultCode);
416        }
417
418        if (mType == TEXTINPUT_ALERT_DIALOG) {
419            i.putExtra("ResultData", mResultData);
420            if (DMClientService.DBG) {
421                logd("onFinish - ResultData: " + mResultData);
422            }
423        } else if (mType == SINGLECHOICE_ALERT_DIALOG) {
424            i.putExtra("ResultCheckedItem", mCheckedItem);
425            if (DMClientService.DBG) {
426                logd("onFinish - ResultCheckedItem: " + mCheckedItem);
427            }
428        } else if (mType == MULTICHOICE_ALERT_DIALOG) {
429            i.putExtra("ResultCheckedItems", mCheckedItems);
430            if (DMClientService.DBG) {
431                logd("onFinish - ResultCheckedItems: "
432                        + Arrays.toString(mCheckedItems));
433            }
434        }
435
436        sendBroadcast(i);
437
438        finish();
439    }
440
441    private void releaseKeyGuardAndWakeLock() {
442        logd("Inside releaseKeyGuardAndWakeLock");
443        if (wl != null) {
444            logd("Releasing the wakelock");
445            wl.release();
446            wl = null;
447        }
448
449        if (mKeyguardLock != null) {
450            logd("Reenable the KeyGuard");
451            mKeyguardLock.reenableKeyguard();
452            mKeyguardLock = null;
453        }
454    }
455
456    private final DialogInterface.OnClickListener mKeyYesClickListener
457            = new DialogInterface.OnClickListener() {
458        @Override
459        public void onClick(DialogInterface dialog, int which) {
460            if (mTimeout > 0) {
461                mHandler.removeCallbacks(mDialogTimeout);
462            }
463
464            if (mType == TEXTINPUT_ALERT_DIALOG) {
465                mResultData = mInputBox.getText().toString();
466            }
467
468            mResultCode = DMAlert.DM_SERVICE_ALERT_RESP_YES;
469            onFinish();
470            if (DMClientService.DBG) {
471                logd("DMAlert.DM_SERVICE_ALERT_RESP_YES");
472            }
473        }
474    };
475
476    private final DialogInterface.OnClickListener mKeyNoClickListener
477            = new DialogInterface.OnClickListener() {
478        @Override
479        public void onClick(DialogInterface dialog, int which) {
480            if (mTimeout > 0) {
481                mHandler.removeCallbacks(mDialogTimeout);
482            }
483
484            mResultCode = DMAlert.DM_SERVICE_ALERT_RESP_NO;
485            onFinish();
486            if (DMClientService.DBG) {
487                logd("DMAlert.DM_SERVICE_ALERT_RESP_NO");
488            }
489        }
490    };
491
492    private final DialogInterface.OnCancelListener mOnCancelListener
493            = new DialogInterface.OnCancelListener() {
494        @Override
495        public void onCancel(DialogInterface dialog) {
496            if (DMClientService.DBG) {
497                logd("OnCancel: Dialog - " + mType);
498            }
499            mResultCode = DMAlert.DM_SERVICE_ALERT_RESP_CANCEL;
500            if (DMClientService.DBG) {
501                logd("DMAlert.DM_SERVICE_ALERT_RESP_CANCEL");
502            }
503            onFinish();
504        }
505    };
506
507    private final DialogInterface.OnClickListener mSingleChoiceClickListener
508            = new DialogInterface.OnClickListener() {
509        @Override
510        public void onClick(DialogInterface dialog, int which) {
511            mCheckedItem = which;
512        }
513    };
514
515    private final DialogInterface.OnMultiChoiceClickListener mMultiChoiceClickListener
516            = new DialogInterface.OnMultiChoiceClickListener() {
517        @Override
518        public void onClick(DialogInterface dialog, int which, boolean isChecked) {
519            mCheckedItems[which] = isChecked;
520        }
521    };
522
523    private static void logd(String msg) {
524        Log.d(TAG, msg);
525    }
526}
527
528