Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f38b1d7a authored by Suprabh Shukla's avatar Suprabh Shukla
Browse files

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
parent 6d296286
Loading
Loading
Loading
Loading
+12 −6
Original line number Diff line number Diff line
@@ -4367,15 +4367,21 @@
    <string name="negative_duration">\u2212<xliff:g id="time" example="1:14">%1$s</xliff:g></string>

    <!-- Title of notification to start a new demo session when device is in retail mode [CHAR LIMIT=NONE] -->
    <string name="reset_retail_demo_mode_title">Restart Session</string>
    <string name="reset_retail_demo_mode_title">Reset device?</string>
    <!-- Text of notification to start a new demo session when device is in retail mode [CHAR LIMIT=NONE] -->
    <string name="reset_retail_demo_mode_text">Tap to start a new demo session</string>
    <string name="reset_retail_demo_mode_text">Tap to reset device</string>
    <!-- Text of dialog shown when starting a demo user for the first time [CHAR LIMIT=40] -->
    <string name="demo_starting_message">Starting demo</string>
    <string name="demo_starting_message">Starting demo\u2026</string>
    <!-- Text of dialog shown when starting a new demo user in retail demo mode [CHAR LIMIT=40] -->
    <string name="demo_restarting_message">Restarting session</string>


    <string name="demo_restarting_message">Resetting device\u2026</string>
    <!-- Title of the dialog shown when user inactivity times out in retail demo mode [CHAR LIMIT=40] -->
    <string name="demo_user_inactivity_timeout_title">Reset device?</string>
    <!-- Warning message shown when user inactivity times out in retail demo mode [CHAR LIMIT=none] -->
    <string name="demo_user_inactivity_timeout_countdown">You\'ll lose any changes and the demo will start again in <xliff:g id="timeout" example="9">%1$s</xliff:g> seconds\u2026</string>
    <!-- Text of button to allow user to abort countdown and continue current session in retail demo mode [CHAR LIMIT=40] -->
    <string name="demo_user_inactivity_timeout_left_button">Cancel</string>
    <!-- Text of button to allow user to abort countdown and immediately start another session in retail demo mode [CHAR LIMIT=40] -->
    <string name="demo_user_inactivity_timeout_right_button">Reset now</string>

    <!-- Title of notification shown when device has been forced to safe mode after a security compromise. -->
    <string name="audit_safemode_notification">Factory reset to use this device without restrictions</string>
+4 −0
Original line number Diff line number Diff line
@@ -1892,6 +1892,10 @@
  <java-symbol type="string" name="audit_safemode_notification_details" />
  <java-symbol type="string" name="reset_retail_demo_mode_title" />
  <java-symbol type="string" name="reset_retail_demo_mode_text" />
  <java-symbol type="string" name="demo_user_inactivity_timeout_title" />
  <java-symbol type="string" name="demo_user_inactivity_timeout_countdown" />
  <java-symbol type="string" name="demo_user_inactivity_timeout_left_button" />
  <java-symbol type="string" name="demo_user_inactivity_timeout_right_button" />

  <java-symbol type="layout" name="resolver_list" />
  <java-symbol type="id" name="resolver_list" />
+33 −9
Original line number Diff line number Diff line
@@ -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;
+109 −0
Original line number Diff line number Diff line
/*
 * 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();
    }
}