From f38b1d7abee34722e9293f7ed78875290369b850 Mon Sep 17 00:00:00 2001 From: Suprabh Shukla Date: Tue, 14 Jun 2016 16:28:23 -0700 Subject: [PATCH] Adding a warning dialog before restarting demo session Instead of immediately restarting the demo after user inactivity timeout, now the system shows a warning dialog that counts down for 6 seconds, during which the user can choose to continue the current session or restart the session immediately. Bug: 29520255 Change-Id: I060f700dcbbb6f64ae5fe95e3f3027bc3c33b38d --- core/res/res/values/strings.xml | 18 ++- core/res/res/values/symbols.xml | 4 + .../server/am/RetailDemoModeService.java | 42 +++++-- .../am/UserInactivityCountdownDialog.java | 109 ++++++++++++++++++ 4 files changed, 158 insertions(+), 15 deletions(-) create mode 100644 services/core/java/com/android/server/am/UserInactivityCountdownDialog.java diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 5db562d16134b..38fec987afefb 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4367,15 +4367,21 @@ \u2212%1$s - Restart Session + Reset device? - Tap to start a new demo session + Tap to reset device - Starting demo + Starting demo\u2026 - Restarting session - - + Resetting device\u2026 + + Reset device? + + You\'ll lose any changes and the demo will start again in %1$s seconds\u2026 + + Cancel + + Reset now Factory reset to use this device without restrictions diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 706d2e6105d35..ecd50bca6f80e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1892,6 +1892,10 @@ + + + + diff --git a/services/core/java/com/android/server/am/RetailDemoModeService.java b/services/core/java/com/android/server/am/RetailDemoModeService.java index 6a5ec9697a419..bcf1bd4cc1d29 100644 --- a/services/core/java/com/android/server/am/RetailDemoModeService.java +++ b/services/core/java/com/android/server/am/RetailDemoModeService.java @@ -25,6 +25,7 @@ import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.IPackageManager; @@ -44,12 +45,13 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.Slog; - import com.android.internal.os.BackgroundThread; import com.android.internal.R; import com.android.internal.widget.LockPatternUtils; import com.android.server.ServiceThread; import com.android.server.SystemService; +import com.android.server.am.UserInactivityCountdownDialog.OnCountDownExpiredListener; + import java.io.File; public class RetailDemoModeService extends SystemService { @@ -65,6 +67,8 @@ public class RetailDemoModeService extends SystemService { private static final long SCREEN_WAKEUP_DELAY = 2500; private static final long USER_INACTIVITY_TIMEOUT = 30000; + private static final long WARNING_DIALOG_TIMEOUT = 6000; + private static final long MILLIS_PER_SECOND = 1000; boolean mDeviceInDemoMode = false; private ActivityManagerService mAms; @@ -110,7 +114,7 @@ public class RetailDemoModeService extends SystemService { mWakeLock.acquire(); break; case MSG_INACTIVITY_TIME_OUT: - IPackageManager pm = AppGlobals.getPackageManager(); + final IPackageManager pm = AppGlobals.getPackageManager(); int enabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; String demoLauncherComponent = getContext().getResources() .getString(R.string.config_demoModeLauncherComponent); @@ -122,8 +126,8 @@ public class RetailDemoModeService extends SystemService { // XXX: shouldn't happen } if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) { - Slog.i(TAG, "Restarting session due to user inactivity timeout"); - sendEmptyMessage(MSG_START_NEW_SESSION); + Slog.i(TAG, "User inactivity timeout reached"); + showInactivityCountdownDialog(); } break; case MSG_START_NEW_SESSION: @@ -131,7 +135,8 @@ public class RetailDemoModeService extends SystemService { Slog.d(TAG, "Switching to a new demo user"); } removeMessages(MSG_START_NEW_SESSION); - UserInfo demoUser = getUserManager().createUser(DEMO_USER_NAME, + removeMessages(MSG_INACTIVITY_TIME_OUT); + final UserInfo demoUser = getUserManager().createUser(DEMO_USER_NAME, UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL); if (demoUser != null) { setupDemoUser(demoUser); @@ -142,6 +147,25 @@ public class RetailDemoModeService extends SystemService { } } + private void showInactivityCountdownDialog() { + UserInactivityCountdownDialog dialog = new UserInactivityCountdownDialog(getContext(), + WARNING_DIALOG_TIMEOUT, MILLIS_PER_SECOND); + dialog.setPositiveButtonClickListener(null); + dialog.setNegativeButtonClickListener(new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mHandler.sendEmptyMessage(MSG_START_NEW_SESSION); + } + }); + dialog.setOnCountDownExpiredListener(new OnCountDownExpiredListener() { + @Override + public void onCountDownExpired() { + mHandler.sendEmptyMessage(MSG_START_NEW_SESSION); + } + }); + dialog.show(); + } + public RetailDemoModeService(Context context) { super(context); } @@ -167,7 +191,7 @@ public class RetailDemoModeService extends SystemService { return mResetDemoPendingIntent; } - void setupDemoUser(UserInfo userInfo) { + private void setupDemoUser(UserInfo userInfo) { UserManager um = getUserManager(); UserHandle user = UserHandle.of(userInfo.id); LockPatternUtils lockPatternUtils = new LockPatternUtils(getContext()); @@ -230,13 +254,13 @@ public class RetailDemoModeService extends SystemService { UserHandle.USER_SYSTEM); } - boolean isDeviceProvisioned() { + private boolean isDeviceProvisioned() { return Settings.Global.getInt( getContext().getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0; } private boolean deleteDemoFolderContents() { - File dir = Environment.getDataPreloadsDemoDirectory(); + final File dir = Environment.getDataPreloadsDemoDirectory(); Slog.i(TAG, "Deleting contents of " + dir); return FileUtils.deleteContents(dir); } @@ -286,7 +310,7 @@ public class RetailDemoModeService extends SystemService { if (DEBUG) { Slog.d(TAG, "onSwitchUser: " + userId); } - UserInfo ui = getUserManager().getUserInfo(userId); + final UserInfo ui = getUserManager().getUserInfo(userId); if (!ui.isDemo()) { Slog.wtf(TAG, "Should not allow switch to non-demo user in demo mode"); return; diff --git a/services/core/java/com/android/server/am/UserInactivityCountdownDialog.java b/services/core/java/com/android/server/am/UserInactivityCountdownDialog.java new file mode 100644 index 0000000000000..1a1e85c847a94 --- /dev/null +++ b/services/core/java/com/android/server/am/UserInactivityCountdownDialog.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.am; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.os.CountDownTimer; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; +import android.widget.TextView; + +import com.android.internal.R; + +public class UserInactivityCountdownDialog extends AlertDialog { + + private OnCountDownExpiredListener mOnCountDownExpiredListener; + private View mDialogView; + private CountDownTimer mCountDownTimer; + private long mCountDownDuration; + private long mRefreshInterval; + + protected UserInactivityCountdownDialog(Context context, long duration, long refreshInterval) { + super(context); + + mCountDownDuration = duration; + mRefreshInterval = refreshInterval; + mDialogView = LayoutInflater.from(context).inflate(R.layout.alert_dialog, null); + String msg = context.getString(R.string.demo_user_inactivity_timeout_countdown, duration); + getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + WindowManager.LayoutParams attrs = getWindow().getAttributes(); + attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; + getWindow().setAttributes(attrs); + setTitle(R.string.demo_user_inactivity_timeout_title); + setView(mDialogView); + setMessage(msg); + } + + public void setOnCountDownExpiredListener( + OnCountDownExpiredListener onCountDownExpiredListener) { + mOnCountDownExpiredListener = onCountDownExpiredListener; + } + + public void setPositiveButtonClickListener(OnClickListener onClickListener) { + setButton(Dialog.BUTTON_POSITIVE, + getContext().getString(R.string.demo_user_inactivity_timeout_left_button), + onClickListener); + } + + public void setNegativeButtonClickListener(OnClickListener onClickListener) { + setButton(Dialog.BUTTON_NEGATIVE, + getContext().getString(R.string.demo_user_inactivity_timeout_right_button), + onClickListener); + } + + @Override + public void show() { + super.show(); + mDialogView.post(new Runnable() { + @Override + public void run() { + mCountDownTimer = new CountDownTimer(mCountDownDuration, mRefreshInterval) { + + @Override + public void onTick(long millisUntilFinished) { + String msg = getContext().getResources().getString( + R.string.demo_user_inactivity_timeout_countdown, + millisUntilFinished / 1000); + ((TextView) mDialogView.findViewById(R.id.message)).setText(msg); + } + + @Override + public void onFinish() { + dismiss(); + if (mOnCountDownExpiredListener != null) + mOnCountDownExpiredListener.onCountDownExpired(); + } + }.start(); + } + }); + } + + @Override + public void dismiss() { + super.dismiss(); + if (mCountDownTimer != null) { + mCountDownTimer.cancel(); + } + } + + interface OnCountDownExpiredListener { + void onCountDownExpired(); + } +}