Skip to content

Commit

Permalink
[SQUASH] base: Add Pocket Mode [1/3]
Browse files Browse the repository at this point in the history
pocket: introduce pocket judge

ZeNiXxX
* Bring to Android 10

DennySPb: adapt to 11, 12

Change-Id: I33153b451f5d38d83e226be0f76bda1ed022dd48

policy: introduce pocket lock

* Block touch screen and keys inputs when device is in pocket.
* Safe-door to disable pocket lock within long press power button
  if sensors do not behave correctly after PocketManager.isDeviceInPocket()
  returns true.
* Window uses TYPE_SYSTEM_ERROR flag with ensure high
  priority over the lockscreen and other high priority windows.
* Do not illuminate buttons when pocket lock is showing.
* Disable fingerprint events and gestures when in pocket
* Be friendly towards Keypress Boost

Contributors:
Carlo Savignano <[email protected]>
Chris Lahaye <[email protected]>
Anas Karbila <[email protected]>
Alex Naidis <[email protected]>
Park Ju Hyung <[email protected]>

Ticket: NOUGAT-15

ZeNiXxX
* Fix  booting issues
* Fix  NPEs
* Bring to Android 10

DennySPb: adapt for 11, 12

Change-Id: I34108fa38f28f15b0b99c8ebb6551dcc4dabad14

pocket: Add hardware acceleration and properly maintain SYSTEM_UI flags

Change-Id: I585598242beec34bd92c5df5836ab395b36cea05

PocketService: Adjust light sensor rate to 400ms

We already adjusted the proximity sensor rate to
400ms, so adjust the rate for the light sensor
accordingly and create a tunable.

Change-Id: Ie6dda80df8cdc677eb6cdb873a5ce1e888572fe7

pocket: introduce pocket bridge

This service communicates pocket state to the pocket judge kernel driver.
It maintains the pocket state by binding to the pocket service.

Ticket: NOUGAT-49

Change-Id: Iee77f767f23d3f77a0d1d871f9305f3b3c6d6630

pocket: Adjust sleep timeout for pocket lock view to 10 secs

 - Fix the case where user sets a high value for sleep timeout in display settings
   and the pocket view is also displayed for that much duration.

Change-Id: If6c4daa1fd98992141f22db70e0e86d5d990f789

pocket: Fix pocket lock view for display cutouts

 - Use LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES layout
   flag to extend pocket lock view for display cutout mode.

Change-Id: I21e4e47cf999b3a0f3d6ebf9165ba9f5596ece0e

Pocket lock improvements

* Fix auto hide not working correctly
* Restore systemui visibility when hidden

ZeNiXxX
* remove faceunlock logic and adapt for android 10

Change-Id: I61b38798d01775b252af88abb01dd2423b3a7638

pocket: Use MD2 lock drawable

Change-Id: Ifb89a68505a9f9b401a2474b5179ea65e9c0e3ce

pocket: Reduce sleep timeout for pocket lock

*if the proximity value changes within 10s, pocketlock exits to lockscreen. Inorder to avoid that reduce timeout to 3s

Change-Id: Iee08801534bebacc2fc62f0bc6e3a0712ce12712

Pocket lock: Add config_pocketModeSupported overlay

Change-Id: I6768c9f8cdd40b2a62df3bd9ddfa04022d69ce10

PocketLock: fix flickering on animations

Change-Id: I4b5499042d0e9ae8f73ecf5c32030d146f640362

PocketJudge: allow register vendor pocket sensor

Some devices (ie OnePlus) have own pocket sensor. This change allow to use
native pocket sensor instead of proximity and light.

Sensor name must be specified in device tree overlay.
In this case PocketService will try to use vendor sensor first.
If sensor wasn't found, fallback sensors (proximity and light) will be in use.

Example for OnePlus sensor:
<string name="config_pocketJudgeVendorSensorName">oneplus.sensor.pocket</string>

Change-Id: Ibe423478cfd9d49e0831e2df0af793178f62c0e0

Fix an edge case in KeyguardUpdateMonitor pocket callback

Change-Id: If872c365ab22bd744c610b136b442ff161c65522

base: Redo Pocket mode view like OOS

Change-Id: I037f5120315581cade60b6c11a64b07cc47ba376

SystemUI: Improve pocket mode layout

Change-Id: I590bc187a5e205102b129fbb9e3625f51b532afd

PocketLock: Make usage of light sensor optional

Some devices with under-display light sensor or other issues might
want to disable this.

Change-Id: I4aed6f080dd562bf3f23ee87d266bc99e039b1fb

base: Allow to define custom pocket sensor value

Not all devices report 1.0 on their pocket mode sensor, Xiaomi for example report 1 if possibly in pocket and 2 if definitely in pocket by their NonUI sensor

Change-Id: Ided2497200153a411ee80484573009a527d34e50

base: Ensure pocket sensor is wakeup

Change-Id: I2784c23ad456e1ce5b042e5cc31f919f6b5a5436

core: Refactor pocket mode interface code

- New illustration created by Radosław Błędowski <[email protected]> for Paranoid Android

Change-Id: Ic224319a7c282158fc1a1855293afb02e056b6ef

base: pocket judge: Don't go to sleep while on call

This causes gdialer to stop vibrations. Let's not

Change-Id: I8e91e021db39a54da6ecfeb2f9475c7d9b227e58

base: pocket judge: Don't mess with power button to reject call

Change-Id: Ifa48f24a14c3e2f94881cfefca6207a4d1d918fa
  • Loading branch information
kaluoshi authored and 33bca committed Jan 13, 2025
1 parent 6e82eff commit 4e75354
Show file tree
Hide file tree
Showing 21 changed files with 2,041 additions and 3 deletions.
1 change: 1 addition & 0 deletions CleanSpec.mk
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/symbols/system/lib/libhwui.so)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libhwui.so)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os/storage/*)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/content/IClipboard.P)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/pocket/*)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/android/internal/telephony/ITelephonyRegistry.P)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/docs/api-stubs*)
Expand Down
11 changes: 11 additions & 0 deletions core/java/android/app/SystemServiceRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@
import android.permission.PermissionCheckerManager;
import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
import android.pocket.IPocketService;
import android.pocket.PocketManager;
import android.print.IPrintManager;
import android.print.PrintManager;
import android.provider.E2eeContactKeysManager;
Expand Down Expand Up @@ -1006,6 +1008,15 @@ public BiometricManager createService(ContextImpl ctx)
}
});

registerService(Context.POCKET_SERVICE, PocketManager.class,
new CachedServiceFetcher<PocketManager>() {
@Override
public PocketManager createService(ContextImpl ctx) {
IBinder binder = ServiceManager.getService(Context.POCKET_SERVICE);
IPocketService service = IPocketService.Stub.asInterface(binder);
return new PocketManager(ctx.getOuterContext(), service);
}});

registerService(Context.TV_INTERACTIVE_APP_SERVICE, TvInteractiveAppManager.class,
new CachedServiceFetcher<TvInteractiveAppManager>() {
@Override
Expand Down
10 changes: 10 additions & 0 deletions core/java/android/content/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -6650,6 +6650,16 @@ public abstract boolean startInstrumentation(@NonNull ComponentName className,
*/
public static final String DC_DIM_SERVICE = "dc_dim";

/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.os.PocketManager} for accessing and listening to device pocket state.
*
* @hide
* @see #getSystemService
* @see android.os.PocketManager
*/
public static final String POCKET_SERVICE = "pocket";

/**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
Expand Down
24 changes: 24 additions & 0 deletions core/java/android/pocket/IPocketCallback.aidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Copyright (C) 2016 The ParanoidAndroid 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 android.pocket;

/** @hide */
interface IPocketCallback {

// notify when pocket state changes.
void onStateChanged(boolean isDeviceInPocket, int reason);

}
43 changes: 43 additions & 0 deletions core/java/android/pocket/IPocketService.aidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Copyright (C) 2016 The ParanoidAndroid 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 android.pocket;

import android.pocket.IPocketCallback;

/** @hide */
interface IPocketService {

// add callback to get notified about pocket state.
void addCallback(IPocketCallback callback);

// remove callback and stop getting notified about pocket state.
void removeCallback(IPocketCallback callback);

// notify pocket service about intercative state changed.
// @see com.android.policy.PhoneWindowManager
void onInteractiveChanged(boolean interactive);

// external processes can request changing listening state.
void setListeningExternal(boolean listen);

// check if device is in pocket.
boolean isDeviceInPocket();

// Custom methods
void setPocketLockVisible(boolean visible);
boolean isPocketLockVisible();

}
28 changes: 28 additions & 0 deletions core/java/android/pocket/PocketConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package android.pocket;

import android.content.res.Resources;

/**
* This class contains global pocket setup constants.
* @author Carlo Savignano
* @hide
*/

public class PocketConstants {

public static final boolean DEBUG = false;
public static final boolean DEBUG_SPEW = false;

/**
* Whether to use proximity sensor to evaluate pocket state.
*/
public static final boolean ENABLE_PROXIMITY_JUDGE = true;

/**
* Whether to use light sensor to evaluate pocket state.
*/
public static final boolean ENABLE_LIGHT_JUDGE = Resources.getSystem().getBoolean(
com.android.internal.R.bool.config_pocketModeLightSensorSupported);


}
237 changes: 237 additions & 0 deletions core/java/android/pocket/PocketManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
/**
* Copyright (C) 2016 The ParanoidAndroid 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 android.pocket;

import android.content.Context;
import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.telecom.TelecomManager;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.Slog;

/**
* A class that coordinates listening for pocket state.
* <p>
* Use {@link android.content.Context#getSystemService(java.lang.String)}
* with argument {@link android.content.Context#POCKET_SERVICE} to get
* an instance of this class.
*
* Usage: import and create a final {@link IPocketCallback.Stub()} and implement your logic in
* {@link IPocketCallback#onStateChanged(boolean, int)}. Then add your callback to the pocket manager
*
* // define a final callback
* private final IPocketCallback mCallback = new IPocketCallback.Stub() {
*
* @Override
* public void onStateChanged(boolean isDeviceInPocket, int reason) {
* // Your method to handle logic outside of this callback, ideally with a handler
* // posting on UI Thread for view hierarchy operations or with its own background thread.
* handlePocketStateChanged(isDeviceInPocket, reason);
* }
*
* }
*
* // add callback to pocket manager
* private void addCallback() {
* PocketManager manager = (PocketManager) context.getSystemService(Context.POCKET_SERVICE);
* manager.addCallback(mCallback);
* }
*
* @author Carlo Savignano
* @hide
*/
public class PocketManager {

private static final String TAG = PocketManager.class.getSimpleName();
static final boolean DEBUG = false;

/**
* Whether {@link IPocketCallback#onStateChanged(boolean, int)}
* was fired because of the sensor.
* @see PocketService#handleDispatchCallbacks()
*/
public static final int REASON_SENSOR = 0;

/**
* Whether {@link IPocketCallback#onStateChanged(boolean, int)}
* was fired because of an error while accessing service.
* @see #addCallback(IPocketCallback)
* @see #removeCallback(IPocketCallback)
*/
public static final int REASON_ERROR = 1;

/**
* Whether {@link IPocketCallback#onStateChanged(boolean, int)}
* was fired because of a needed reset.
* @see PocketService#binderDied()
*/
public static final int REASON_RESET = 2;

private Context mContext;
private IPocketService mService;
private PowerManager mPowerManager;
private TelecomManager mTelecomManager;
private Handler mHandler;
private boolean mPocketViewTimerActive;

public PocketManager(Context context, IPocketService service) {
mContext = context;
mService = service;
if (mService == null) {
Slog.v(TAG, "PocketService was null");
}
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
mHandler = new Handler();
}

/**
* Add pocket state callback.
* @see PocketService#handleRemoveCallback(IPocketCallback)
*/
public void addCallback(final IPocketCallback callback) {
if (mService != null) try {
mService.addCallback(callback);
} catch (RemoteException e1) {
Log.w(TAG, "Remote exception in addCallback: ", e1);
if (callback != null){
try {
callback.onStateChanged(false, REASON_ERROR);
} catch (RemoteException e2) {
Log.w(TAG, "Remote exception in callback.onPocketStateChanged: ", e2);
}
}
}
}

/**
* Remove pocket state callback.
* @see PocketService#handleAddCallback(IPocketCallback)
*/
public void removeCallback(final IPocketCallback callback) {
if (mService != null) try {
mService.removeCallback(callback);
} catch (RemoteException e1) {
Log.w(TAG, "Remote exception in removeCallback: ", e1);
if (callback != null){
try {
callback.onStateChanged(false, REASON_ERROR);
} catch (RemoteException e2) {
Log.w(TAG, "Remote exception in callback.onPocketStateChanged: ", e2);
}
}
}
}

/**
* Notify service about device interactive state changed.
* {@link PhoneWindowManager#startedWakingUp()}
* {@link PhoneWindowManager#startedGoingToSleep(int)}
*/
public void onInteractiveChanged(boolean interactive) {
boolean isPocketViewShowing = (interactive && isDeviceInPocket());
synchronized (mPocketLockTimeout) {
if (mPocketViewTimerActive != isPocketViewShowing) {
if (isPocketViewShowing) {
if (DEBUG) Log.v(TAG, "Setting pocket timer");
mHandler.removeCallbacks(mPocketLockTimeout); // remove any pending requests
mHandler.postDelayed(mPocketLockTimeout, 3 * DateUtils.SECOND_IN_MILLIS);
mPocketViewTimerActive = true;
} else {
if (DEBUG) Log.v(TAG, "Clearing pocket timer");
mHandler.removeCallbacks(mPocketLockTimeout);
mPocketViewTimerActive = false;
}
}
}
if (mService != null) try {
mService.onInteractiveChanged(interactive);
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in addCallback: ", e);
}
}

/**
* Request listening state change by, but not limited to, external process.
* @see PocketService#handleSetListeningExternal(boolean)
*/
public void setListeningExternal(boolean listen) {
if (mService != null) try {
mService.setListeningExternal(listen);
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in setListeningExternal: ", e);
}
// Clear timeout when user hides pocket lock with long press power.
if (mPocketViewTimerActive && !listen) {
if (DEBUG) Log.v(TAG, "Clearing pocket timer due to override");
mHandler.removeCallbacks(mPocketLockTimeout);
mPocketViewTimerActive = false;
}
}

/**
* Return whether device is in pocket.
* @see PocketService#isDeviceInPocket()
* @return
*/
public boolean isDeviceInPocket() {
if (mService != null) try {
return mService.isDeviceInPocket();
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in isDeviceInPocket: ", e);
}
return false;
}

class PocketLockTimeout implements Runnable {
@Override
public void run() {
if (!mTelecomManager.isInCall())
mPowerManager.goToSleep(SystemClock.uptimeMillis());
mPocketViewTimerActive = false;
}
}

/** Custom methods **/

public void setPocketLockVisible(boolean visible) {
if (!visible){
if (DEBUG) Log.v(TAG, "Clearing pocket timer");
mHandler.removeCallbacks(mPocketLockTimeout);
mPocketViewTimerActive = false;
}
if (mService != null) try {
mService.setPocketLockVisible(visible);
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in setPocketLockVisible: ", e);
}
}

public boolean isPocketLockVisible() {
if (mService != null) try {
return mService.isPocketLockVisible();
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in isPocketLockVisible: ", e);
}
return false;
}

private PocketLockTimeout mPocketLockTimeout = new PocketLockTimeout();

}
Loading

0 comments on commit 4e75354

Please sign in to comment.