summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jason Monk <jmonk@google.com> 2014-05-21 16:06:19 -0400
committer Jason Monk <jmonk@google.com> 2014-06-20 16:17:38 -0400
commit62515beee67307d8859beec521b7baedfa54b2b5 (patch)
treee08c69d802fb9929a223c626fe33662a47350085
parent65dfc83cef6dd936deef428f1d318d10ff1d7af5 (diff)
Add lock-to-app mode
Added a dialog that shows when app has not been authorized by DevicePolicyManager.isLockTaskAuthorized. This allows any app to trigger lock-to-app mode. This same dialog is used when startLockTaskOnCurrent is triggered by the recents long-press. Can exit the mode by long-pressing recents again. Keyguard is disabled when lock-to-app is active. This CL also prevents apps from finishing when they are the root task in a lock task TaskRecord. Change-Id: Ib54d858e570cccf6bfd986958868e15f49bcef75
-rw-r--r--core/java/android/app/Activity.java14
-rw-r--r--core/java/android/app/ActivityManagerNative.java36
-rw-r--r--core/java/android/app/IActivityManager.java8
-rw-r--r--core/java/android/provider/Settings.java12
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_open_wht_24dp.pngbin0 -> 390 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_outline_wht_24dp.pngbin0 -> 391 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_recent.pngbin0 -> 688 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_open_wht_24dp.pngbin0 -> 294 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_outline_wht_24dp.pngbin0 -> 294 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_recent.pngbin0 -> 472 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lock_open_wht_24dp.pngbin0 -> 523 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_lock_outline_wht_24dp.pngbin0 -> 530 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_recent.pngbin0 -> 598 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/ic_lock_open_wht_24dp.pngbin0 -> 717 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/ic_lock_outline_wht_24dp.pngbin0 -> 722 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/ic_recent.pngbin0 -> 1074 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/ic_lock_open_wht_24dp.pngbin0 -> 930 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/ic_lock_outline_wht_24dp.pngbin0 -> 932 bytes
-rw-r--r--core/res/res/drawable/lock_task_notify_bg.xml22
-rw-r--r--core/res/res/layout/lock_to_app_enter.xml44
-rw-r--r--core/res/res/layout/lock_to_app_exit.xml45
-rw-r--r--core/res/res/values/strings.xml13
-rw-r--r--core/res/res/values/symbols.xml8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java1
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java115
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java54
-rw-r--r--services/core/java/com/android/server/am/LockTaskNotify.java185
-rw-r--r--services/core/java/com/android/server/am/LockToAppRequestDialog.java87
29 files changed, 641 insertions, 37 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 91328832794e..d0d028908bf0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -30,6 +30,7 @@ import com.android.internal.policy.PolicyManager;
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.app.admin.DevicePolicyManager;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -5935,14 +5936,21 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Put this Activity in a mode where the user is locked to the
+ * Request to put this Activity in a mode where the user is locked to the
* current task.
*
* This will prevent the user from launching other apps, going to settings,
* or reaching the home screen.
*
- * Lock task mode will only start if the activity has been whitelisted by the
- * Device Owner through DevicePolicyManager#setLockTaskComponents.
+ * If {@link DevicePolicyManager#isLockTaskPermitted(String)} returns true
+ * for this component then the app will go directly into Lock Task mode. The user
+ * will not be able to exit this mode until {@link Activity#stopLockTask()} is called.
+ *
+ * If {@link DevicePolicyManager#isLockTaskPermitted(String)} returns false
+ * then the system will prompt the user with a dialog requesting permission to enter
+ * this mode. When entered through this method the user can exit at any time by
+ * swiping down twice from the top of the screen. Calling stopLockTask will also
+ * exit the mode.
*/
public void startLockTask() {
try {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 56462ae73680..572d389651d4 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2145,6 +2145,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case START_LOCK_TASK_BY_CURRENT: {
+ data.enforceInterface(IActivityManager.descriptor);
+ startLockTaskModeOnCurrent();
+ reply.writeNoException();
+ return true;
+ }
+
case STOP_LOCK_TASK_MODE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
stopLockTaskMode();
@@ -2152,6 +2159,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case STOP_LOCK_TASK_BY_CURRENT: {
+ data.enforceInterface(IActivityManager.descriptor);
+ stopLockTaskModeOnCurrent();
+ reply.writeNoException();
+ return true;
+ }
+
case IS_IN_LOCK_TASK_MODE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
final boolean isInLockTaskMode = isInLockTaskMode();
@@ -4947,6 +4961,17 @@ class ActivityManagerProxy implements IActivityManager
}
@Override
+ public void startLockTaskModeOnCurrent() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(START_LOCK_TASK_BY_CURRENT, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ @Override
public void stopLockTaskMode() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -4958,6 +4983,17 @@ class ActivityManagerProxy implements IActivityManager
}
@Override
+ public void stopLockTaskModeOnCurrent() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(STOP_LOCK_TASK_BY_CURRENT, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ @Override
public boolean isInLockTaskMode() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index bf2d7e5969ba..b630278d2318 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -429,6 +429,9 @@ public interface IActivityManager extends IInterface {
public IBinder getHomeActivityToken() throws RemoteException;
/** @hide */
+ public void startLockTaskModeOnCurrent() throws RemoteException;
+
+ /** @hide */
public void startLockTaskMode(int taskId) throws RemoteException;
/** @hide */
@@ -438,6 +441,9 @@ public interface IActivityManager extends IInterface {
public void stopLockTaskMode() throws RemoteException;
/** @hide */
+ public void stopLockTaskModeOnCurrent() throws RemoteException;
+
+ /** @hide */
public boolean isInLockTaskMode() throws RemoteException;
/** @hide */
@@ -744,4 +750,6 @@ public interface IActivityManager extends IInterface {
int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
int GET_ACTIVITY_OPTIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+219;
int GET_APP_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+220;
+ int START_LOCK_TASK_BY_CURRENT = IBinder.FIRST_CALL_TRANSACTION+221;
+ int STOP_LOCK_TASK_BY_CURRENT = IBinder.FIRST_CALL_TRANSACTION+222;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 06c05eedc8ab..733bdadacf1c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2460,6 +2460,18 @@ public final class Settings {
public static final String POINTER_SPEED = "pointer_speed";
/**
+ * Whether lock-to-app will be triggered by long-press on recents.
+ * @hide
+ */
+ public static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled";
+
+ /**
+ * Whether lock-to-app will lock the keyguard when exiting.
+ * @hide
+ */
+ public static final String LOCK_TO_APP_EXIT_LOCKED = "lock_to_app_exit_locked";
+
+ /**
* I am the lolrus.
* <p>
* Nonzero values indicate that the user has a bukkit.
diff --git a/core/res/res/drawable-hdpi/ic_lock_open_wht_24dp.png b/core/res/res/drawable-hdpi/ic_lock_open_wht_24dp.png
new file mode 100644
index 000000000000..4d97045cbdcd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_open_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_outline_wht_24dp.png b/core/res/res/drawable-hdpi/ic_lock_outline_wht_24dp.png
new file mode 100644
index 000000000000..46fb463ec4ab
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_outline_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_recent.png b/core/res/res/drawable-hdpi/ic_recent.png
new file mode 100644
index 000000000000..8866539c5d77
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_recent.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_open_wht_24dp.png b/core/res/res/drawable-mdpi/ic_lock_open_wht_24dp.png
new file mode 100644
index 000000000000..163f4a0b48a7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_open_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_outline_wht_24dp.png b/core/res/res/drawable-mdpi/ic_lock_outline_wht_24dp.png
new file mode 100644
index 000000000000..bbfb83c7f1e1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_outline_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_recent.png b/core/res/res/drawable-mdpi/ic_recent.png
new file mode 100644
index 000000000000..2b607df07c97
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_recent.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lock_open_wht_24dp.png b/core/res/res/drawable-xhdpi/ic_lock_open_wht_24dp.png
new file mode 100644
index 000000000000..21d4d5355168
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lock_open_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lock_outline_wht_24dp.png b/core/res/res/drawable-xhdpi/ic_lock_outline_wht_24dp.png
new file mode 100644
index 000000000000..2aeb9a2da0bb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lock_outline_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_recent.png b/core/res/res/drawable-xhdpi/ic_recent.png
new file mode 100644
index 000000000000..86316dbb84ef
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_recent.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lock_open_wht_24dp.png b/core/res/res/drawable-xxhdpi/ic_lock_open_wht_24dp.png
new file mode 100644
index 000000000000..1b11b597247d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lock_open_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lock_outline_wht_24dp.png b/core/res/res/drawable-xxhdpi/ic_lock_outline_wht_24dp.png
new file mode 100644
index 000000000000..ae0d655d0d46
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lock_outline_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_recent.png b/core/res/res/drawable-xxhdpi/ic_recent.png
new file mode 100644
index 000000000000..e6bd1256bff7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_recent.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_lock_open_wht_24dp.png b/core/res/res/drawable-xxxhdpi/ic_lock_open_wht_24dp.png
new file mode 100644
index 000000000000..877441207c8e
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_lock_open_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_lock_outline_wht_24dp.png b/core/res/res/drawable-xxxhdpi/ic_lock_outline_wht_24dp.png
new file mode 100644
index 000000000000..1375accd5c9c
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_lock_outline_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable/lock_task_notify_bg.xml b/core/res/res/drawable/lock_task_notify_bg.xml
new file mode 100644
index 000000000000..3a8fab51900d
--- /dev/null
+++ b/core/res/res/drawable/lock_task_notify_bg.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle" >
+
+ <solid android:color="@android:color/black" />
+ <corners
+ android:radius="8dip" />
+</shape>
diff --git a/core/res/res/layout/lock_to_app_enter.xml b/core/res/res/layout/lock_to_app_enter.xml
new file mode 100644
index 000000000000..c034536f27f0
--- /dev/null
+++ b/core/res/res/layout/lock_to_app_enter.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="20dp"
+ android:paddingRight="20dp"
+ android:paddingBottom="12dp"
+ android:alpha=".8"
+ android:background="@drawable/lock_task_notify_bg" >
+
+ <ImageView
+ android:id="@+id/lock_icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="20dp"
+ android:alpha=".8"
+ android:src="@drawable/ic_lock_outline_wht_24dp" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/lock_icon"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="2dp"
+ android:textColor="@android:color/white"
+ android:alpha=".8"
+ android:text="@string/lock_to_app_start" />
+</RelativeLayout>
diff --git a/core/res/res/layout/lock_to_app_exit.xml b/core/res/res/layout/lock_to_app_exit.xml
new file mode 100644
index 000000000000..4a60c80e9b13
--- /dev/null
+++ b/core/res/res/layout/lock_to_app_exit.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="20dp"
+ android:paddingRight="20dp"
+ android:paddingBottom="12dp"
+ android:alpha=".8"
+ android:background="@drawable/lock_task_notify_bg" >
+
+ <ImageView
+ android:id="@+id/lock_icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="20dp"
+ android:alpha=".8"
+ android:src="@drawable/ic_lock_open_wht_24dp" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/lock_icon"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="2dp"
+ android:textColor="@android:color/white"
+ android:alpha=".8"
+ android:text="@string/lock_to_app_exit" />
+</RelativeLayout>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c8c0d236bdd6..e017f53e8880 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4746,4 +4746,17 @@
<!-- DO NOT TRANSLATE -->
<string name="day_of_week_label_typeface">sans-serif</string>
+ <!-- Lock-to-app dialog title. -->
+ <string name="lock_to_app_title">Use lock-to-app?</string>
+ <!-- Lock-to-app dialog description. The $ is not actually shown or translated, it is a marker of where the recents icon shows up. -->
+ <string name="lock_to_app_description">Lock-to-app locks the display in a single app.\n\nTo exit press and hold the recent apps button $</string>
+ <!-- Lock-to-app negative response. -->
+ <string name="lock_to_app_negative">NO</string>
+ <!-- Lock-to-app positive response. -->
+ <string name="lock_to_app_positive">START</string>
+ <!-- Starting lock-to-app indication. -->
+ <string name="lock_to_app_start">Start Lock-to-app</string>
+ <!-- Exting lock-to-app indication. -->
+ <string name="lock_to_app_exit">Exit Lock-to-app</string>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1547bbdcfb3f..7d0d75972b37 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -604,6 +604,14 @@
<java-symbol type="string" name="kilobyteShort" />
<java-symbol type="string" name="last_month" />
<java-symbol type="string" name="launchBrowserDefault" />
+ <java-symbol type="string" name="lock_to_app_title" />
+ <java-symbol type="string" name="lock_to_app_description" />
+ <java-symbol type="string" name="lock_to_app_negative" />
+ <java-symbol type="string" name="lock_to_app_positive" />
+ <java-symbol type="drawable" name="ic_recent" />
+ <java-symbol type="layout" name="lock_to_app_enter" />
+ <java-symbol type="layout" name="lock_to_app_exit" />
+ <java-symbol type="drawable" name="lock_task_notify_bg" />
<java-symbol type="string" name="lockscreen_access_pattern_cell_added" />
<java-symbol type="string" name="lockscreen_access_pattern_cleared" />
<java-symbol type="string" name="lockscreen_access_pattern_detected" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 1da7dabb55be..f57b79726c18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -35,6 +35,7 @@ import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
@@ -64,6 +65,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
+import android.provider.Settings.SettingNotFoundException;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
@@ -893,6 +895,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
};
+ private View.OnLongClickListener mLockToAppClickListener = new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ toggleLockedApp();
+ return true;
+ }
+ };
+
private int mShowSearchHoldoff = 0;
private Runnable mShowSearchPanel = new Runnable() {
public void run() {
@@ -936,6 +946,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
+ mNavigationBarView.getRecentsButton().setLongClickable(true);
+ mNavigationBarView.getRecentsButton().setOnLongClickListener(mLockToAppClickListener);
mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
updateSearchPanel();
}
@@ -3133,6 +3145,28 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mStackScroller.setAnimationsEnabled(true);
}
+ public void toggleLockedApp() {
+ Log.d(TAG, "Trying to toggle lock-to-app");
+ try {
+ IActivityManager activityManager = ActivityManagerNative.getDefault();
+ if (activityManager.isInLockTaskMode()) {
+ activityManager.stopLockTaskModeOnCurrent();
+ } else {
+ try {
+ boolean lockToAppEnabled = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.LOCK_TO_APP_ENABLED) != 0;
+ if (lockToAppEnabled) {
+ activityManager.startLockTaskModeOnCurrent();
+ }
+ } catch (SettingNotFoundException e) {
+ // No setting, not enabled.
+ }
+ }
+ } catch (RemoteException e) {
+ Log.d(TAG, "Unable to toggle Lock-to-app", e);
+ }
+ }
+
private final Runnable mUserActivity = new Runnable() {
@Override
public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 330b599fe3b9..0134fe85b1bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -63,6 +63,7 @@ public class KeyButtonView extends ImageView {
// Just an old-fashioned ImageView
performLongClick();
}
+ setPressed(false);
}
}
};
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 34c1ecd7b72f..5dd1a14a9cea 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -36,6 +36,9 @@ import android.app.IActivityContainerCallback;
import android.app.IAppTask;
import android.app.admin.DevicePolicyManager;
import android.appwidget.AppWidgetManager;
+import android.content.DialogInterface.OnClickListener;
+import android.content.res.Resources;
+import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.os.BatteryStats;
import android.os.PersistableBundle;
@@ -171,8 +174,12 @@ import android.os.SystemProperties;
import android.os.UpdateLock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.text.Spannable;
+import android.text.SpannableString;
import android.text.format.DateUtils;
import android.text.format.Time;
+import android.text.style.DynamicDrawableSpan;
+import android.text.style.ImageSpan;
import android.util.AtomicFile;
import android.util.EventLog;
import android.util.Log;
@@ -186,6 +193,7 @@ import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
+import android.widget.TextView;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -1158,6 +1166,8 @@ public final class ActivityManagerService extends ActivityManagerNative
CompatModeDialog mCompatModeDialog;
long mLastMemUsageReportTime = 0;
+ private LockToAppRequestDialog mLockToAppRequest;
+
/**
* Flag whether the current user is a "monkey", i.e. whether
* the UI is driven by a UI automation tool.
@@ -2176,6 +2186,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
};
+ mLockToAppRequest = new LockToAppRequestDialog(mContext, this);
+
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
}
@@ -3662,6 +3674,12 @@ public final class ActivityManagerService extends ActivityManagerNative
// Keep track of the root activity of the task before we finish it
TaskRecord tr = r.task;
ActivityRecord rootR = tr.getRootActivity();
+ // Do not allow task to finish in Lock Task mode.
+ if (tr == mStackSupervisor.mLockTaskModeTask) {
+ if (rootR == r) {
+ return false;
+ }
+ }
if (mController != null) {
// Find the first activity that is not finishing.
ActivityRecord next = r.task.stack.topRunningActivityLocked(token, 0);
@@ -3806,13 +3824,25 @@ public final class ActivityManagerService extends ActivityManagerNative
public boolean finishActivityAffinity(IBinder token) {
synchronized(this) {
final long origId = Binder.clearCallingIdentity();
- ActivityRecord r = ActivityRecord.isInStackLocked(token);
- boolean res = false;
- if (r != null) {
- res = r.task.stack.finishActivityAffinityLocked(r);
+ try {
+ ActivityRecord r = ActivityRecord.isInStackLocked(token);
+
+ ActivityRecord rootR = r.task.getRootActivity();
+ // Do not allow task to finish in Lock Task mode.
+ if (r.task == mStackSupervisor.mLockTaskModeTask) {
+ if (rootR == r) {
+ Binder.restoreCallingIdentity(origId);
+ return false;
+ }
+ }
+ boolean res = false;
+ if (r != null) {
+ res = r.task.stack.finishActivityAffinityLocked(r);
+ }
+ return res;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- Binder.restoreCallingIdentity(origId);
- return res;
}
}
@@ -7642,12 +7672,20 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- private void startLockTaskMode(TaskRecord task) {
+ void startLockTaskMode(TaskRecord task) {
final String pkg;
synchronized (this) {
pkg = task.intent.getComponent().getPackageName();
}
- if (!isLockTaskAuthorized(pkg)) {
+ boolean isSystemInitiated = Binder.getCallingUid() == Process.SYSTEM_UID;
+ if (!isSystemInitiated && !isLockTaskAuthorized(pkg)) {
+ final TaskRecord taskRecord = task;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mLockToAppRequest.showLockTaskPrompt(taskRecord);
+ }
+ });
return;
}
long ident = Binder.clearCallingIdentity();
@@ -7659,7 +7697,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if ((mFocusedActivity == null) || (task != mFocusedActivity.task)) {
throw new IllegalArgumentException("Invalid task, not in foreground");
}
- mStackSupervisor.setLockTaskModeLocked(task);
+ mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated);
}
}
} finally {
@@ -7704,24 +7742,55 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
+ public void startLockTaskModeOnCurrent() throws RemoteException {
+ checkCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS);
+ ActivityRecord r = null;
+ synchronized (this) {
+ r = mStackSupervisor.topRunningActivityLocked();
+ }
+ startLockTaskMode(r.task);
+ }
+
+ @Override
public void stopLockTaskMode() {
// Verify that the user matches the package of the intent for the TaskRecord
- // we are locked to. This will ensure the same caller for startLockTaskMode and
- // stopLockTaskMode.
+ // we are locked to or systtem. This will ensure the same caller for startLockTaskMode
+ // and stopLockTaskMode.
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ try {
+ String pkg =
+ mStackSupervisor.mLockTaskModeTask.intent.getComponent().getPackageName();
+ int uid = mContext.getPackageManager().getPackageUid(pkg,
+ Binder.getCallingUserHandle().getIdentifier());
+ if (uid != callingUid) {
+ throw new SecurityException("Invalid uid, expected " + uid);
+ }
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "stopLockTaskMode " + e);
+ return;
+ }
+ }
+ long ident = Binder.clearCallingIdentity();
try {
- String pkg = mStackSupervisor.mLockTaskModeTask.intent.getPackage();
- int uid = mContext.getPackageManager().getPackageUid(pkg,
- Binder.getCallingUserHandle().getIdentifier());
- if (uid != Binder.getCallingUid()) {
- throw new SecurityException("Invalid uid, expected " + uid);
+ Log.d(TAG, "stopLockTaskMode");
+ // Stop lock task
+ synchronized (this) {
+ mStackSupervisor.setLockTaskModeLocked(null, false);
}
- } catch (NameNotFoundException e) {
- Log.d(TAG, "stopLockTaskMode " + e);
- return;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- // Stop lock task
- synchronized (this) {
- mStackSupervisor.setLockTaskModeLocked(null);
+ }
+
+ @Override
+ public void stopLockTaskModeOnCurrent() throws RemoteException {
+ checkCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ stopLockTaskMode();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -16651,7 +16720,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return true;
}
- mStackSupervisor.setLockTaskModeLocked(null);
+ mStackSupervisor.setLockTaskModeLocked(null, false);
final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
if (userInfo == null) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 9264186c6329..6f2996c73501 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -79,6 +79,8 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.service.voice.IVoiceInteractionSession;
import android.util.EventLog;
import android.util.Slog;
@@ -142,6 +144,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay";
+ private static final String LOCK_TASK_TAG = "Lock-to-App";
+
/** Status Bar Service **/
private IBinder mToken = new Binder();
private IStatusBarService mStatusBarService;
@@ -255,6 +259,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
/** If non-null then the task specified remains in front and no other tasks may be started
* until the task exits or #stopLockTaskMode() is called. */
TaskRecord mLockTaskModeTask;
+ /**
+ * Notifies the user when entering/exiting lock-task.
+ */
+ private LockTaskNotify mLockTaskNotify;
public ActivityStackSupervisor(ActivityManagerService service) {
mService = service;
@@ -3004,7 +3012,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
return list;
}
- void setLockTaskModeLocked(TaskRecord task) {
+ void setLockTaskModeLocked(TaskRecord task, boolean showHomeRecents) {
if (task == null) {
// Take out of lock task mode if necessary
if (mLockTaskModeTask != null) {
@@ -3028,6 +3036,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
lockTaskMsg.obj = mLockTaskModeTask.intent.getComponent().getPackageName();
lockTaskMsg.arg1 = mLockTaskModeTask.userId;
lockTaskMsg.what = LOCK_TASK_START_MSG;
+ lockTaskMsg.arg2 = showHomeRecents ? 1 : 0;
mHandler.sendMessage(lockTaskMsg);
}
@@ -3130,15 +3139,24 @@ public final class ActivityStackSupervisor implements DisplayListener {
case LOCK_TASK_START_MSG: {
// When lock task starts, we disable the status bars.
try {
+ if (mLockTaskNotify == null) {
+ mLockTaskNotify = new LockTaskNotify(mService.mContext);
+ }
+ mLockTaskNotify.show(true);
if (getStatusBarService() != null) {
- getStatusBarService().disable
- (StatusBarManager.DISABLE_MASK ^ StatusBarManager.DISABLE_BACK,
- mToken, mService.mContext.getPackageName());
+ int flags =
+ StatusBarManager.DISABLE_MASK ^ StatusBarManager.DISABLE_BACK;
+ if (msg.arg2 != 0) {
+ flags ^= StatusBarManager.DISABLE_HOME
+ | StatusBarManager.DISABLE_RECENT;
+ }
+ getStatusBarService().disable(flags, mToken,
+ mService.mContext.getPackageName());
}
+ mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG);
if (getDevicePolicyManager() != null) {
getDevicePolicyManager().notifyLockTaskModeChanged(true,
- (String)msg.obj,
- msg.arg1);
+ (String)msg.obj, msg.arg1);
}
} catch (RemoteException ex) {
throw new RuntimeException(ex);
@@ -3147,15 +3165,29 @@ public final class ActivityStackSupervisor implements DisplayListener {
case LOCK_TASK_END_MSG: {
// When lock task ends, we enable the status bars.
try {
- if (getStatusBarService() != null) {
- getStatusBarService().disable
- (StatusBarManager.DISABLE_NONE,
- mToken, mService.mContext.getPackageName());
- }
+ if (getStatusBarService() != null) {
+ getStatusBarService().disable(StatusBarManager.DISABLE_NONE, mToken,
+ mService.mContext.getPackageName());
+ }
+ mWindowManager.reenableKeyguard(mToken);
if (getDevicePolicyManager() != null) {
getDevicePolicyManager().notifyLockTaskModeChanged(false, null,
msg.arg1);
}
+ if (mLockTaskNotify == null) {
+ mLockTaskNotify = new LockTaskNotify(mService.mContext);
+ }
+ mLockTaskNotify.show(false);
+ try {
+ boolean shouldLockKeyguard = Settings.System.getInt(
+ mService.mContext.getContentResolver(),
+ Settings.System.LOCK_TO_APP_EXIT_LOCKED) != 0;
+ if (shouldLockKeyguard) {
+ mWindowManager.lockNow(null);
+ }
+ } catch (SettingNotFoundException e) {
+ // No setting, don't lock.
+ }
} catch (RemoteException ex) {
throw new RuntimeException(ex);
}
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
new file mode 100644
index 000000000000..1997f4619a21
--- /dev/null
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2013 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.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.Message;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import com.android.internal.R;
+
+/**
+ * Helper to manage showing/hiding a image to notify them that they are entering
+ * or exiting lock-to-app mode.
+ */
+public class LockTaskNotify {
+ private static final String TAG = "LockTaskNotify";
+
+ private static final int SHOW_LENGTH_MS = 1500;
+
+ private final Context mContext;
+ private final H mHandler;
+
+ private ClingWindowView mClingWindow;
+ private WindowManager mWindowManager;
+ private boolean mIsStarting;
+
+ public LockTaskNotify(Context context) {
+ mContext = context;
+ mHandler = new H();
+ mWindowManager = (WindowManager)
+ mContext.getSystemService(Context.WINDOW_SERVICE);
+ }
+
+ public void show(boolean starting) {
+ mIsStarting = starting;
+ mHandler.obtainMessage(H.SHOW).sendToTarget();
+ }
+
+ public WindowManager.LayoutParams getClingWindowLayoutParams() {
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_TOAST,
+ 0
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+ ,
+ PixelFormat.TRANSLUCENT);
+ lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ lp.setTitle("LockTaskNotify");
+ lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
+ lp.gravity = Gravity.FILL;
+ return lp;
+ }
+
+ public FrameLayout.LayoutParams getImageLayoutParams() {
+ return new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
+ }
+
+ private void handleShow() {
+ mClingWindow = new ClingWindowView(mContext);
+
+ // we will be hiding the nav bar, so layout as if it's already hidden
+ mClingWindow.setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+
+ // show the confirmation
+ WindowManager.LayoutParams lp = getClingWindowLayoutParams();
+ mWindowManager.addView(mClingWindow, lp);
+ }
+
+ private void handleHide() {
+ if (mClingWindow != null) {
+ mWindowManager.removeView(mClingWindow);
+ mClingWindow = null;
+ }
+ }
+
+
+ private class ClingWindowView extends FrameLayout {
+ private View mView;
+
+ private Runnable mUpdateLayoutRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mView != null && mView.getParent() != null) {
+ mView.setLayoutParams(getImageLayoutParams());
+ }
+ }
+ };
+
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+ post(mUpdateLayoutRunnable);
+ }
+ }
+ };
+
+ public ClingWindowView(Context context) {
+ super(context);
+ setClickable(true);
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ mWindowManager.getDefaultDisplay().getMetrics(metrics);
+
+ int id = R.layout.lock_to_app_exit;
+ if (mIsStarting) {
+ id = R.layout.lock_to_app_enter;
+ }
+ mView = View.inflate(getContext(), id, null);
+
+ addView(mView, getImageLayoutParams());
+
+ mContext.registerReceiver(mReceiver,
+ new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(H.HIDE), SHOW_LENGTH_MS);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ mContext.unregisterReceiver(mReceiver);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent motion) {
+ Slog.v(TAG, "ClingWindowView.onTouchEvent");
+ return true;
+ }
+ }
+
+ private final class H extends Handler {
+ private static final int SHOW = 1;
+ private static final int HIDE = 2;
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case SHOW:
+ handleShow();
+ break;
+ case HIDE:
+ handleHide();
+ break;
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/LockToAppRequestDialog.java b/services/core/java/com/android/server/am/LockToAppRequestDialog.java
new file mode 100644
index 000000000000..6e86dff1c54a
--- /dev/null
+++ b/services/core/java/com/android/server/am/LockToAppRequestDialog.java
@@ -0,0 +1,87 @@
+
+package com.android.server.am;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.res.Resources;
+import android.graphics.BitmapFactory;
+import android.provider.Settings;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.DynamicDrawableSpan;
+import android.text.style.ImageSpan;
+import android.util.Slog;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+public class LockToAppRequestDialog implements OnClickListener {
+ private static final String TAG = "ActivityManager";
+
+ final private Context mContext;
+ final private ActivityManagerService mService;
+
+ private AlertDialog mDialog;
+ private TaskRecord mRequestedTask;
+
+ public LockToAppRequestDialog(Context context, ActivityManagerService activityManagerService) {
+ mContext = context;
+ mService = activityManagerService;
+ }
+
+ public void showLockTaskPrompt(TaskRecord task) {
+ if (mDialog != null) {
+ mDialog.dismiss();
+ mDialog = null;
+ }
+ mRequestedTask = task;
+
+ final Resources r = Resources.getSystem();
+ final String descriptionString = r.getString(R.string.lock_to_app_description);
+ final SpannableString description =
+ new SpannableString(descriptionString.replace('$', ' '));
+ final ImageSpan imageSpan = new ImageSpan(mContext,
+ BitmapFactory.decodeResource(r, R.drawable.ic_recent),
+ DynamicDrawableSpan.ALIGN_BOTTOM);
+ final int index = descriptionString.indexOf('$');
+ if (index >= 0) {
+ description.setSpan(imageSpan, index, index + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ mDialog =
+ new AlertDialog.Builder(mContext)
+ .setTitle(r.getString(R.string.lock_to_app_title))
+ .setMessage(description)
+ .setPositiveButton(r.getString(R.string.lock_to_app_positive), this)
+ .setNegativeButton(r.getString(R.string.lock_to_app_negative), this)
+ .create();
+
+ mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ mDialog.show();
+
+ // Make icon fit.
+ final TextView msgTxt = (TextView) mDialog.findViewById(R.id.message);
+ final float width = imageSpan.getDrawable().getIntrinsicWidth();
+ final float height = imageSpan.getDrawable().getIntrinsicHeight();
+ final int lineHeight = msgTxt.getLineHeight();
+ imageSpan.getDrawable().setBounds(0, 0, (int) (lineHeight * width / height), lineHeight);
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (DialogInterface.BUTTON_POSITIVE == which) {
+ Slog.d(TAG, "accept lock-to-app request");
+ // Automatically enable if not currently on. (Could be triggered by an app)
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.LOCK_TO_APP_ENABLED, 1);
+
+ // Start lock-to-app.
+ mService.startLockTaskMode(mRequestedTask);
+ } else {
+ Slog.d(TAG, "ignore lock-to-app request");
+ }
+ }
+
+}