sm8150-common: Import XiaomiParts from sm8250-common

* As of 3f51ae9799
* Minus thermal implementation

Change-Id: Ic48d1a02e875b2c7a5146608745a7d7a63499901
This commit is contained in:
Sebastiano Barezzi
2022-06-23 16:15:33 +02:00
parent e807b0f841
commit f6f8c4e56f
27 changed files with 1875 additions and 0 deletions

View File

@@ -142,6 +142,10 @@ PRODUCT_PACKAGES += \
android.hardware.ir@1.0-impl \
android.hardware.ir@1.0-service
# Device-specific settings
PRODUCT_PACKAGES += \
XiaomiParts
# Display
PRODUCT_PACKAGES += \
android.hardware.graphics.composer@2.4-impl \

25
parts/Android.bp Normal file
View File

@@ -0,0 +1,25 @@
//
// Copyright (C) 2017-2022 The LineageOS Project
//
// SPDX-License-Identifier: Apache-2.0
//
android_app {
name: "XiaomiParts",
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
certificate: "platform",
platform_apis: true,
system_ext_specific: true,
privileged: true,
static_libs: [
"org.lineageos.settings.resources",
"//hardware/xiaomi:vendor.xiaomi.hardware.motor-V1.0-java",
],
optimize: {
proguard_flags_files: ["proguard.flags"],
},
}

90
parts/AndroidManifest.xml Normal file
View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015-2016 The CyanogenMod Project
2017-2022 The LineageOS 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.lineageos.settings"
android:versionCode="1"
android:versionName="1.0"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<protected-broadcast android:name="com.android.systemui.doze.pulse" />
<uses-sdk
android:minSdkVersion="24"
android:targetSdkVersion="24"/>
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/device_settings_app_name"
android:persistent="true"
android:theme="@style/Theme.SubSettingsBase">
<receiver android:name=".BootCompletedReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<service android:name=".doze.DozeService"
android:permission="XiaomiDozeService">
</service>
<service
android:name=".popupcamera.PopupCameraService"
android:permission="PopupCameraService">
</service>
<activity
android:name=".doze.DozeSettingsActivity"
android:label="@string/ambient_display_title">
<intent-filter>
<action android:name="org.lineageos.settings.device.DOZE_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".popupcamera.PopupCameraSettingsActivity"
android:label="@string/popup_title"
android:theme="@style/Theme.SubSettingsBase"
android:enabled="false">
<intent-filter>
<action android:name="com.android.settings.action.IA_SETTINGS" />
</intent-filter>
<meta-data
android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.system" />
<meta-data
android:name="com.android.settings.icon"
android:resource="@drawable/ic_settings_popup" />
<meta-data
android:name="com.android.settings.summary"
android:resource="@string/summary_empty" />
<meta-data
android:name="com.android.settings.order"
android:value="-255" />
</activity>
</application>
</manifest>

7
parts/proguard.flags Normal file
View File

@@ -0,0 +1,7 @@
-keep class org.lineageos.settings.doze.* {
*;
}
-keep class org.lineageos.settings.popupcamera.* {
*;
}

View File

@@ -0,0 +1,9 @@
<!-- drawable/hand.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorControlNormal" >
<path android:fillColor="#000" android:pathData="M6.58,19H14.58V22H6.58V19M19.74,11.6C19.55,11.4 19.29,11.28 19,11.28L18.78,11.31L15.58,13V11.83L16.09,2.9C16.12,2.35 15.7,1.87 15.15,1.84C14.6,1.81 14.12,2.23 14.09,2.78L13.82,7.47H13.58L12.54,7.58V2A1,1 0 0,0 11.54,1C11,1 10.54,1.45 10.54,2V8.41L9.72,8.78L9.03,3.32C8.96,2.77 8.46,2.38 7.91,2.45C7.36,2.5 6.97,3 7.04,3.57L7.81,9.63L7.43,9.8C7.3,9.85 7.18,9.93 7.07,10L5.97,6.11C5.81,5.54 5.25,5.2 4.71,5.34C4.18,5.5 3.88,6.08 4.04,6.65L6.61,15.77C6.61,15.8 6.63,15.84 6.64,15.87L6.67,16H6.68C6.9,16.57 7.47,17 8.08,17H14.58C14.97,17 15.32,16.84 15.58,16.57L20.5,12.37L19.74,11.6Z" />
</vector>

View File

@@ -0,0 +1,9 @@
<!-- drawable/arrow_decision_outline.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorControlNormal" >
<path android:fillColor="#000" android:pathData="M9.64,13.4C8.63,12.5 7.34,12.03 6,12V15L2,11L6,7V10C7.67,10 9.3,10.57 10.63,11.59C10.22,12.15 9.89,12.76 9.64,13.4M18,15V12C17.5,12 13.5,12.16 13.05,16.2C14.61,16.75 15.43,18.47 14.88,20.03C14.33,21.59 12.61,22.41 11.05,21.86C9.5,21.3 8.67,19.59 9.22,18.03C9.5,17.17 10.2,16.5 11.05,16.2C11.34,12.61 14.4,9.88 18,10V7L22,11L18,15M13,19A1,1 0 0,0 12,18A1,1 0 0,0 11,19A1,1 0 0,0 12,20A1,1 0 0,0 13,19M11,11.12C11.58,10.46 12.25,9.89 13,9.43V5H16L12,1L8,5H11V11.12Z" />
</vector>

View File

@@ -0,0 +1,9 @@
<!-- drawable/pocket.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorControlNormal" >
<path android:fillColor="#000" android:pathData="M21.9,4.26C21.64,3.55 20.96,3.07 20.2,3.07H20.19L18.46,3.07H3.81C3.07,3.07 2.39,3.54 2.12,4.24C2.04,4.45 2,4.66 2,4.88V10.92L2.07,12.12C2.36,14.85 3.78,17.23 5.97,18.9C6,18.93 6.05,18.96 6.09,19H6.11C7.29,19.86 8.6,20.44 10,20.73C10.68,20.86 11.35,20.93 12,20.93C12.63,20.93 13.25,20.87 13.85,20.76C13.93,20.75 14,20.73 14.07,20.72C14.09,20.71 14.11,20.7 14.14,20.69C15.5,20.4 16.76,19.83 17.89,19H17.91C17.95,18.96 18,18.93 18.03,18.9C20.22,17.23 21.64,14.85 21.93,12.12L22,10.92V4.88C22,4.68 21.97,4.47 21.9,4.26M17.67,10.55L12.96,15.06C12.7,15.32 12.35,15.44 12,15.44C11.67,15.44 11.33,15.32 11.06,15.06L6.36,10.55C5.81,10.03 5.79,9.16 6.32,8.61C6.84,8.06 7.71,8.05 8.26,8.57L12,12.17L15.77,8.57C16.31,8.05 17.18,8.07 17.71,8.61C18.23,9.16 18.21,10.03 17.67,10.55Z" />
</vector>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?android:attr/colorControlNormal"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M10,20L5,20v2h5v2l3,-3 -3,-3v2zM14,20v2h5v-2h-5zM12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -1.99,0.9 -1.99,2S10.9,8 12,8zM17,0L7,0C5.9,0 5,0.9 5,2v14c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,2c0,-1.1 -0.9,-2 -2,-2zM7,2h10v10.5c0,-1.67 -3.33,-2.5 -5,-2.5s-5,0.83 -5,2.5L7,2z" />
</vector>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The LineageOS 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.
-->
<resources>
<!-- Popup camera effect names -->
<string-array name="popupcamera_effects_names" translatable="false">
<item>popup_muqin_up.ogg</item>
<item>popup_muqin_down.ogg</item>
<item>popup_yingyan_up.ogg</item>
<item>popup_yingyan_down.ogg</item>
<item>popup_mofa_up.ogg</item>
<item>popup_mofa_down.ogg</item>
<item>popup_jijia_up.ogg</item>
<item>popup_jijia_down.ogg</item>
<item>popup_chilun_up.ogg</item>
<item>popup_chilun_down.ogg</item>
<item>popup_cangmen_up.ogg</item>
<item>popup_cangmen_down.ogg</item>
</string-array>
<string-array name="popupcamera_effects_entries">
<item>@string/action_none</item>
<item>@string/popup_title_muqin</item>
<item>@string/popup_title_yingyan</item>
<item>@string/popup_title_mofa</item>
<item>@string/popup_title_jijia</item>
<item>@string/popup_title_chilun</item>
<item>@string/popup_title_cangmen</item>
</string-array>
<string-array name="popupcamera_effects_values">
<item>-1</item>
<item>0</item>
<item>2</item>
<item>4</item>
<item>6</item>
<item>8</item>
<item>10</item>
</string-array>
</resources>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2020-2022 The LineageOS 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.
-->
<resources>
<!-- Ambient settings -->
<string name="ambient_enable">Use Ambient display</string>
<!-- Popup camera settings -->
<string name="popup_led_title">Camera LED</string>
<string name="popup_led_summary">Show LED light when the front camera appears and retracts</string>
<string name="popup_title">Front camera sound effects</string>
<string name="popup_title_muqin">Xylophone</string>
<string name="popup_title_yingyan">Condor</string>
<string name="popup_title_mofa">Magic</string>
<string name="popup_title_jijia">Mecha</string>
<string name="popup_title_chilun">Gearwheel</string>
<string name="popup_title_cangmen">Cabin door</string>
<!-- Popup camera strings -->
<string name="popup_camera_tip">Warning</string>
<string name="popup_camera_takeback_failed_times_calibrate">Couldn\'t close front camera multiple times. Try calibrating the camera.</string>
<string name="popup_camera_popup_failed_times_calibrate">Couldn\'t open front camera multiple times. Try calibrating the camera.</string>
<string name="popup_camera_calibrate_running">Front camera cannot be used during calibration.</string>
<string name="popup_camera_calibrate_now">Calibrate</string>
<string name="popup_camera_calibrate_failed">Couldn\'t calibrate</string>
<string name="popup_camera_calibrate_success">Calibrated successfully. You can open the front camera now.</string>
<string name="stop_operate_camera_frequently">You\'re opening the front camera too frequently.</string>
<string name="takeback_camera_front_failed">Couldn\'t close front camera. Try again.</string>
<string name="popup_camera_front_failed">Couldn\'t open front camera. Try again.</string>
</resources>

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The CyanogenMod Project
2018-2019,2021 The LineageOS 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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/ambient_display_title">
<com.android.settingslib.widget.MainSwitchPreference
android:defaultValue="false"
android:key="doze_enable"
android:title="@string/ambient_enable" />
<SwitchPreference
android:key="always_on_display"
android:disableDependentsState="true"
android:title="@string/ambient_display_always_on_title"
android:summary="@string/ambient_display_always_on_summary"
android:persistent="false" />
<PreferenceCategory
android:key="pickup_sensor"
android:title="@string/pickup_sensor_title">
<SwitchPreference
android:key="gesture_pick_up"
android:defaultValue="false"
android:icon="@drawable/ic_pickup"
android:title="@string/pick_up_gesture_title"
android:summary="@string/pick_up_gesture_summary" />
</PreferenceCategory>
<PreferenceCategory
android:key="proximity_sensor"
android:title="@string/proximity_sensor_title">
<SwitchPreference
android:key="gesture_hand_wave"
android:defaultValue="false"
android:icon="@drawable/ic_hand"
android:title="@string/hand_wave_gesture_title"
android:summary="@string/hand_wave_gesture_summary" />
<SwitchPreference
android:key="gesture_pocket"
android:defaultValue="false"
android:icon="@drawable/ic_pocket"
android:title="@string/pocket_gesture_title"
android:summary="@string/pocket_gesture_summary" />
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreference
android:defaultValue="true"
android:key="popup_led_effect"
android:summary="@string/popup_led_summary"
android:title="@string/popup_led_title" />
<ListPreference
android:defaultValue="0"
android:entries="@array/popupcamera_effects_entries"
android:entryValues="@array/popupcamera_effects_values"
android:key="popup_sound_effect"
android:summary="%s"
android:title="@string/popup_title" />
</PreferenceScreen>

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-2020 The LineageOS 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 org.lineageos.settings;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import org.lineageos.settings.doze.DozeUtils;
import org.lineageos.settings.popupcamera.PopupCameraUtils;
public class BootCompletedReceiver extends BroadcastReceiver {
private static final boolean DEBUG = false;
private static final String TAG = "XiaomiParts";
@Override
public void onReceive(final Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "Received boot completed intent");
DozeUtils.checkDozeService(context);
PopupCameraUtils.checkPopupCameraService(context);
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-2020 The LineageOS 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 org.lineageos.settings.doze;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;
import org.lineageos.settings.sensors.PickupSensor;
import org.lineageos.settings.sensors.ProximitySensor;
public class DozeService extends Service {
private static final String TAG = "DozeService";
private static final boolean DEBUG = false;
private ProximitySensor mProximitySensor;
private PickupSensor mPickupSensor;
private BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
onDisplayOn();
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
onDisplayOff();
}
}
};
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "Creating service");
mProximitySensor = new ProximitySensor(this);
mPickupSensor = new PickupSensor(this);
IntentFilter screenStateFilter = new IntentFilter();
screenStateFilter.addAction(Intent.ACTION_SCREEN_ON);
screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mScreenStateReceiver, screenStateFilter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "Starting service");
return START_STICKY;
}
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "Destroying service");
super.onDestroy();
this.unregisterReceiver(mScreenStateReceiver);
mProximitySensor.disable();
mPickupSensor.disable();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void onDisplayOn() {
if (DEBUG) Log.d(TAG, "Display on");
if (DozeUtils.isPickUpEnabled(this)) {
mPickupSensor.disable();
}
if (DozeUtils.isHandwaveGestureEnabled(this) ||
DozeUtils.isPocketGestureEnabled(this)) {
mProximitySensor.disable();
}
}
private void onDisplayOff() {
if (DEBUG) Log.d(TAG, "Display off");
if (DozeUtils.isPickUpEnabled(this)) {
mPickupSensor.enable();
}
if (DozeUtils.isHandwaveGestureEnabled(this) ||
DozeUtils.isPocketGestureEnabled(this)) {
mProximitySensor.enable();
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2015-2016 The CyanogenMod Project
* 2017,2021 The LineageOS 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 org.lineageos.settings.doze;
import android.os.Bundle;
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
import com.android.settingslib.collapsingtoolbar.R;
public class DozeSettingsActivity extends CollapsingToolbarBaseActivity {
private static final String TAG_DOZE = "doze";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(R.id.content_frame,
new DozeSettingsFragment(), TAG_DOZE).commit();
}
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-2019,2021 The LineageOS 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 org.lineageos.settings.doze;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.widget.Switch;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragment;
import androidx.preference.SwitchPreference;
import com.android.settingslib.widget.MainSwitchPreference;
import com.android.settingslib.widget.OnMainSwitchChangeListener;
import org.lineageos.settings.R;
public class DozeSettingsFragment extends PreferenceFragment implements
Preference.OnPreferenceChangeListener, OnMainSwitchChangeListener {
private MainSwitchPreference mSwitchBar;
private SwitchPreference mAlwaysOnDisplayPreference;
private SwitchPreference mPickUpPreference;
private SwitchPreference mHandwavePreference;
private SwitchPreference mPocketPreference;
private Handler mHandler = new Handler();
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.doze_settings);
SharedPreferences prefs = getActivity().getSharedPreferences("doze_settings",
Activity.MODE_PRIVATE);
if (savedInstanceState == null && !prefs.getBoolean("first_help_shown", false)) {
showHelp();
}
boolean dozeEnabled = DozeUtils.isDozeEnabled(getActivity());
mSwitchBar = (MainSwitchPreference) findPreference(DozeUtils.DOZE_ENABLE);
mSwitchBar.addOnSwitchChangeListener(this);
mSwitchBar.setChecked(dozeEnabled);
mAlwaysOnDisplayPreference = (SwitchPreference) findPreference(DozeUtils.ALWAYS_ON_DISPLAY);
mAlwaysOnDisplayPreference.setEnabled(dozeEnabled);
mAlwaysOnDisplayPreference.setChecked(DozeUtils.isAlwaysOnEnabled(getActivity()));
mAlwaysOnDisplayPreference.setOnPreferenceChangeListener(this);
PreferenceCategory pickupSensorCategory = (PreferenceCategory) getPreferenceScreen().
findPreference(DozeUtils.CATEG_PICKUP_SENSOR);
PreferenceCategory proximitySensorCategory = (PreferenceCategory) getPreferenceScreen().
findPreference(DozeUtils.CATEG_PROX_SENSOR);
mPickUpPreference = (SwitchPreference) findPreference(DozeUtils.GESTURE_PICK_UP_KEY);
mPickUpPreference.setEnabled(dozeEnabled);
mPickUpPreference.setOnPreferenceChangeListener(this);
mHandwavePreference = (SwitchPreference) findPreference(DozeUtils.GESTURE_HAND_WAVE_KEY);
mHandwavePreference.setEnabled(dozeEnabled);
mHandwavePreference.setOnPreferenceChangeListener(this);
mPocketPreference = (SwitchPreference) findPreference(DozeUtils.GESTURE_POCKET_KEY);
mPocketPreference.setEnabled(dozeEnabled);
mPocketPreference.setOnPreferenceChangeListener(this);
// Hide proximity sensor related features if the device doesn't support them
if (!DozeUtils.getProxCheckBeforePulse(getActivity())) {
getPreferenceScreen().removePreference(proximitySensorCategory);
}
// Hide AOD if not supported and set all its dependents otherwise
if (!DozeUtils.alwaysOnDisplayAvailable(getActivity())) {
getPreferenceScreen().removePreference(mAlwaysOnDisplayPreference);
} else {
pickupSensorCategory.setDependency(DozeUtils.ALWAYS_ON_DISPLAY);
proximitySensorCategory.setDependency(DozeUtils.ALWAYS_ON_DISPLAY);
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (DozeUtils.ALWAYS_ON_DISPLAY.equals(preference.getKey())) {
DozeUtils.enableAlwaysOn(getActivity(), (Boolean) newValue);
}
mHandler.post(() -> DozeUtils.checkDozeService(getActivity()));
return true;
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
DozeUtils.enableDoze(getActivity(), isChecked);
DozeUtils.checkDozeService(getActivity());
mSwitchBar.setChecked(isChecked);
if (!isChecked) {
DozeUtils.enableAlwaysOn(getActivity(), false);
mAlwaysOnDisplayPreference.setChecked(false);
}
mAlwaysOnDisplayPreference.setEnabled(isChecked);
mPickUpPreference.setEnabled(isChecked);
mHandwavePreference.setEnabled(isChecked);
mPocketPreference.setEnabled(isChecked);
}
private void showHelp() {
HelpDialogFragment fragment = new HelpDialogFragment();
fragment.show(getFragmentManager(), "help_dialog");
}
private static class HelpDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.doze_settings_help_title)
.setMessage(R.string.doze_settings_help_text)
.setNegativeButton(R.string.dialog_ok, (dialog, which) -> dialog.cancel())
.create();
}
@Override
public void onCancel(DialogInterface dialog) {
getActivity().getSharedPreferences("doze_settings", Activity.MODE_PRIVATE)
.edit()
.putBoolean("first_help_shown", true)
.commit();
}
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-2019,2021 The LineageOS 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 org.lineageos.settings.doze;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import androidx.preference.PreferenceManager;
import static android.provider.Settings.Secure.DOZE_ALWAYS_ON;
import static android.provider.Settings.Secure.DOZE_ENABLED;
public final class DozeUtils {
protected static final String DOZE_ENABLE = "doze_enable";
protected static final String ALWAYS_ON_DISPLAY = "always_on_display";
protected static final String CATEG_PICKUP_SENSOR = "pickup_sensor";
protected static final String CATEG_PROX_SENSOR = "proximity_sensor";
protected static final String GESTURE_PICK_UP_KEY = "gesture_pick_up";
protected static final String GESTURE_HAND_WAVE_KEY = "gesture_hand_wave";
protected static final String GESTURE_POCKET_KEY = "gesture_pocket";
private static final String TAG = "DozeUtils";
private static final boolean DEBUG = false;
private static final String DOZE_INTENT = "com.android.systemui.doze.pulse";
public static void startService(Context context) {
if (DEBUG) Log.d(TAG, "Starting service");
context.startServiceAsUser(new Intent(context, DozeService.class),
UserHandle.CURRENT);
}
protected static void stopService(Context context) {
if (DEBUG) Log.d(TAG, "Stopping service");
context.stopServiceAsUser(new Intent(context, DozeService.class),
UserHandle.CURRENT);
}
public static void checkDozeService(Context context) {
if (isDozeEnabled(context) && !isAlwaysOnEnabled(context) && sensorsEnabled(context)) {
startService(context);
} else {
stopService(context);
}
}
protected static boolean getProxCheckBeforePulse(Context context) {
try {
Context con = context.createPackageContext("com.android.systemui", 0);
int id = con.getResources().getIdentifier("doze_proximity_check_before_pulse",
"bool", "com.android.systemui");
return con.getResources().getBoolean(id);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
protected static boolean enableDoze(Context context, boolean enable) {
return Settings.Secure.putInt(context.getContentResolver(),
DOZE_ENABLED, enable ? 1 : 0);
}
public static boolean isDozeEnabled(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
DOZE_ENABLED, 1) != 0;
}
public static void launchDozePulse(Context context) {
if (DEBUG) Log.d(TAG, "Launch doze pulse");
context.sendBroadcastAsUser(new Intent(DOZE_INTENT),
new UserHandle(UserHandle.USER_CURRENT));
}
protected static boolean enableAlwaysOn(Context context, boolean enable) {
return Settings.Secure.putIntForUser(context.getContentResolver(),
DOZE_ALWAYS_ON, enable ? 1 : 0, UserHandle.USER_CURRENT);
}
protected static boolean isAlwaysOnEnabled(Context context) {
final boolean enabledByDefault = context.getResources()
.getBoolean(com.android.internal.R.bool.config_dozeAlwaysOnEnabled);
return Settings.Secure.getIntForUser(context.getContentResolver(),
DOZE_ALWAYS_ON, alwaysOnDisplayAvailable(context) && enabledByDefault ? 1 : 0,
UserHandle.USER_CURRENT) != 0;
}
protected static boolean alwaysOnDisplayAvailable(Context context) {
return new AmbientDisplayConfiguration(context).alwaysOnAvailable();
}
protected static boolean isGestureEnabled(Context context, String gesture) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(gesture, false);
}
public static boolean isPickUpEnabled(Context context) {
return isGestureEnabled(context, GESTURE_PICK_UP_KEY);
}
public static boolean isHandwaveGestureEnabled(Context context) {
return isGestureEnabled(context, GESTURE_HAND_WAVE_KEY);
}
public static boolean isPocketGestureEnabled(Context context) {
return isGestureEnabled(context, GESTURE_POCKET_KEY);
}
public static boolean sensorsEnabled(Context context) {
return isPickUpEnabled(context) || isHandwaveGestureEnabled(context)
|| isPocketGestureEnabled(context);
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2020 The LineageOS 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 org.lineageos.settings.popupcamera;
public class Constants {
public static final int CAMERA_EVENT_DELAY_TIME = 100; // ms
public static final int MSG_CAMERA_CLOSED = 1001;
public static final int MSG_CAMERA_OPEN = 1002;
public static final int MOTOR_STATUS_CALIB_ERROR = 18;
public static final int MOTOR_STATUS_CALIB_OK = 17;
public static final int MOTOR_STATUS_CANCELED = 20;
public static final int MOTOR_STATUS_DROPPED = 16;
public static final int MOTOR_STATUS_INVALID = 10;
public static final int MOTOR_STATUS_MAX = 20;
public static final int MOTOR_STATUS_MIN = 10;
public static final int MOTOR_STATUS_NOT_INIT = -1;
public static final int MOTOR_STATUS_POPUP_JAMMED = 12;
public static final int MOTOR_STATUS_POPUP_OK = 11;
public static final int MOTOR_STATUS_PRESSED = 15;
public static final int MOTOR_STATUS_REQUEST_CALIB = 19;
public static final int MOTOR_STATUS_TAKEBACK_JAMMED = 14;
public static final int MOTOR_STATUS_TAKEBACK_OK = 13;
public static final String CLOSE_CAMERA_STATE = "0";
public static final String OPEN_CAMERA_STATE = "1";
public static final String FRONT_CAMERA_ID = "1";
public static final String BLUE_LED_PATH = "/sys/class/leds/blue/breath";
public static final String GREEN_LED_PATH =
"/sys/class/leds/green/breath";
public static final String RED_LED_PATH = "/sys/class/leds/red/breath";
public static final String BLUE_RIGHT_LED_PATH =
"/sys/class/leds/blue-right/breath";
public static final String GREEN_RIGHT_LED_PATH =
"/sys/class/leds/green-right/breath";
public static final String RED_RIGHT_LED_PATH =
"/sys/class/leds/red-right/breath";
public static final String POPUP_SOUND_PATH = "/system_ext/media/audio/ui/";
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2019 The LineageOS 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 org.lineageos.settings.popupcamera;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
public class PopupCameraPreferences {
private static final String TAG = "PopupCameraUtils";
private static final boolean DEBUG = false;
private static final String LED_EFFECT_KEY = "popup_led_effect";
private static final boolean LED_EFFECT_DEFAULT_VALUE = true;
private static final String SOUND_EFFECT_KEY = "popup_sound_effect";
private static final String SOUND_EFFECT_DEFAULT_VALUE = "0";
private SharedPreferences mSharedPrefs;
public PopupCameraPreferences(Context context) {
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
}
public String getSoundEffect() {
return mSharedPrefs.getString(SOUND_EFFECT_KEY, SOUND_EFFECT_DEFAULT_VALUE);
}
public boolean isLedAllowed() {
return mSharedPrefs.getBoolean(LED_EFFECT_KEY, LED_EFFECT_DEFAULT_VALUE);
}
}

View File

@@ -0,0 +1,413 @@
/*
* Copyright (C) 2019 The LineageOS 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 org.lineageos.settings.popupcamera;
import android.annotation.NonNull;
import android.app.AlertDialog;
import android.app.Service;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.camera2.CameraManager;
import android.media.AudioAttributes;
import android.media.SoundPool;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Toast;
import org.lineageos.settings.R;
import org.lineageos.settings.sensors.ProximitySensor;
import org.lineageos.settings.sensors.SensorsUtils;
import org.lineageos.settings.utils.FileUtils;
import vendor.xiaomi.hardware.motor.V1_0.IMotor;
import vendor.xiaomi.hardware.motor.V1_0.IMotorCallback;
import vendor.xiaomi.hardware.motor.V1_0.MotorEvent;
import java.util.NoSuchElementException;
public class PopupCameraService extends Service implements Handler.Callback {
private static final String TAG = "PopupCameraService";
private static final boolean DEBUG = false;
private IMotor mMotor = null;
private final Object mLock = new Object();
private boolean mMotorBusy = false;
private long mClosedEvent;
private long mOpenEvent;
private Handler mHandler = new Handler(this);
private boolean mMotorCalibrating = false;
private boolean mErrorDialogShowing;
private PopupCameraPreferences mPopupCameraPreferences;
private SensorManager mSensorManager;
private Sensor mFreeFallSensor;
private ProximitySensor mProximitySensor;
private int[] mSounds;
private SoundPool mSoundPool;
private IMotorCallback mMotorCallback = new IMotorCallback.Stub() {
@Override
public void onNotify(MotorEvent event) {
int status = event.vaalue;
int cookie = event.cookie;
if (DEBUG)
Log.d(TAG, "onNotify: cookie=" + cookie + ",status=" + status);
synchronized (mLock) {
if (status == Constants.MOTOR_STATUS_CALIB_OK ||
status == Constants.MOTOR_STATUS_CALIB_ERROR) {
mMotorCalibrating = false;
showCalibrationResult(status);
} else if (status == Constants.MOTOR_STATUS_PRESSED) {
updateMotor(Constants.CLOSE_CAMERA_STATE);
goBackHome();
} else if (status == Constants.MOTOR_STATUS_POPUP_JAMMED ||
status == Constants.MOTOR_STATUS_TAKEBACK_JAMMED) {
showErrorDialog();
}
}
}
};
private CameraManager.AvailabilityCallback mAvailabilityCallback =
new CameraManager.AvailabilityCallback() {
@Override
public void onCameraClosed(@NonNull String cameraId) {
super.onCameraClosed(cameraId);
if (cameraId.equals(Constants.FRONT_CAMERA_ID)) {
mClosedEvent = SystemClock.elapsedRealtime();
if (SystemClock.elapsedRealtime() - mOpenEvent <
Constants.CAMERA_EVENT_DELAY_TIME &&
mHandler.hasMessages(Constants.MSG_CAMERA_OPEN)) {
mHandler.removeMessages(Constants.MSG_CAMERA_OPEN);
}
mHandler.sendEmptyMessageDelayed(Constants.MSG_CAMERA_CLOSED,
Constants.CAMERA_EVENT_DELAY_TIME);
}
}
@Override
public void onCameraOpened(@NonNull String cameraId, @NonNull String packageId) {
super.onCameraOpened(cameraId, packageId);
if (cameraId.equals(Constants.FRONT_CAMERA_ID)) {
mOpenEvent = SystemClock.elapsedRealtime();
if (SystemClock.elapsedRealtime() - mClosedEvent <
Constants.CAMERA_EVENT_DELAY_TIME &&
mHandler.hasMessages(Constants.MSG_CAMERA_CLOSED)) {
mHandler.removeMessages(Constants.MSG_CAMERA_CLOSED);
}
mHandler.sendEmptyMessageDelayed(Constants.MSG_CAMERA_OPEN,
Constants.CAMERA_EVENT_DELAY_TIME);
}
}
};
private SensorEventListener mFreeFallListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
if (event.values[0] == 2.0f) {
updateMotor(Constants.CLOSE_CAMERA_STATE);
goBackHome();
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
// Service
@Override
public void onCreate() {
CameraManager cameraManager = getSystemService(CameraManager.class);
cameraManager.registerAvailabilityCallback(mAvailabilityCallback, null);
mSensorManager = getSystemService(SensorManager.class);
mFreeFallSensor = SensorsUtils.getSensor(mSensorManager, "xiaomi.sensor.free_fall");
mProximitySensor = new ProximitySensor(this);
mPopupCameraPreferences = new PopupCameraPreferences(this);
mSoundPool = new SoundPool.Builder()
.setMaxStreams(1)
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
.build())
.build();
String[] soundNames = getResources().getStringArray(R.array.popupcamera_effects_names);
mSounds = new int[soundNames.length];
for (int i = 0; i < soundNames.length; i++) {
mSounds[i] = mSoundPool.load(Constants.POPUP_SOUND_PATH + soundNames[i], 1);
}
IMotor motor = getMotor();
if (motor == null) {
return;
}
try {
int status = motor.getMotorStatus();
if (status == Constants.MOTOR_STATUS_POPUP_OK ||
status == Constants.MOTOR_STATUS_POPUP_JAMMED ||
status == Constants.MOTOR_STATUS_TAKEBACK_JAMMED) {
mHandler.sendEmptyMessage(Constants.MSG_CAMERA_CLOSED);
}
} catch (RemoteException e) {
// Do nothing
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG)
Log.d(TAG, "Starting service");
IMotor motor = getMotor();
if (motor == null) {
return START_STICKY;
}
mProximitySensor.enable();
return START_STICKY;
}
@Override
public void onDestroy() {
if (DEBUG)
Log.d(TAG, "Destroying service");
IMotor motor = getMotor();
if (motor == null) {
return;
}
mProximitySensor.disable();
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
// Handler.Callback
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case Constants.MSG_CAMERA_CLOSED: {
updateMotor(Constants.CLOSE_CAMERA_STATE);
}
break;
case Constants.MSG_CAMERA_OPEN: {
updateMotor(Constants.OPEN_CAMERA_STATE);
}
break;
}
return true;
}
static public IMotor getMotorService() {
IMotor motor = null;
try {
motor = IMotor.getService();
} catch (NoSuchElementException | RemoteException e) {
// Do nothing
}
return motor;
}
public IMotor getMotor() {
if (mMotor == null) {
try {
mMotor = getMotorService();
if (mMotor != null) {
mMotor.setMotorCallback(mMotorCallback);
mMotor.asBinder().linkToDeath((cookie) -> {
mMotor = null;
}, 0);
}
} catch (RemoteException e) {
// Do nothing
}
}
return mMotor;
}
private void updateMotor(String cameraState) {
IMotor motor = getMotor();
if (motor == null || mProximitySensor.getSawNear()) {
return;
}
final Runnable r = () -> {
mMotorBusy = true;
try {
int status = motor.getMotorStatus();
if (DEBUG)
Log.d(TAG, "updateMotor: status=" + status);
if (cameraState.equals(Constants.OPEN_CAMERA_STATE) &&
motor.getMotorStatus() == Constants.MOTOR_STATUS_TAKEBACK_OK) {
lightUp();
playSoundEffect(Constants.OPEN_CAMERA_STATE);
motor.popupMotor(1);
mSensorManager.registerListener(mFreeFallListener, mFreeFallSensor,
SensorManager.SENSOR_DELAY_NORMAL);
} else if (cameraState.equals(Constants.CLOSE_CAMERA_STATE) &&
motor.getMotorStatus() == Constants.MOTOR_STATUS_POPUP_OK) {
lightUp();
playSoundEffect(Constants.CLOSE_CAMERA_STATE);
motor.takebackMotor(1);
mSensorManager.unregisterListener(mFreeFallListener, mFreeFallSensor);
} else {
mMotorBusy = false;
if (status == Constants.MOTOR_STATUS_REQUEST_CALIB ||
status == Constants.MOTOR_STATUS_POPUP_JAMMED ||
status == Constants.MOTOR_STATUS_TAKEBACK_JAMMED ||
status == Constants.MOTOR_STATUS_CALIB_ERROR) {
showErrorDialog();
}
return;
}
} catch (RemoteException e) {
// Do nothing
}
mHandler.postDelayed(() -> mMotorBusy = false, 1200);
};
if (mMotorBusy) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (mMotorBusy) {
mHandler.postDelayed(this, 100);
} else {
mHandler.post(r);
}
}
}, 100);
} else {
mHandler.post(r);
}
}
private void lightUp() {
if (mPopupCameraPreferences.isLedAllowed()) {
FileUtils.writeLine(Constants.RED_LED_PATH, "1");
FileUtils.writeLine(Constants.GREEN_LED_PATH, "1");
FileUtils.writeLine(Constants.BLUE_LED_PATH, "1");
FileUtils.writeLine(Constants.RED_RIGHT_LED_PATH, "1");
FileUtils.writeLine(Constants.GREEN_RIGHT_LED_PATH, "1");
FileUtils.writeLine(Constants.BLUE_RIGHT_LED_PATH, "1");
mHandler.postDelayed(() -> {
FileUtils.writeLine(Constants.RED_LED_PATH, "0");
FileUtils.writeLine(Constants.GREEN_LED_PATH, "0");
FileUtils.writeLine(Constants.BLUE_LED_PATH, "0");
FileUtils.writeLine(Constants.RED_RIGHT_LED_PATH, "0");
FileUtils.writeLine(Constants.GREEN_RIGHT_LED_PATH, "0");
FileUtils.writeLine(Constants.BLUE_RIGHT_LED_PATH, "0");
}, 2300);
}
}
private void calibrateMotor() {
synchronized (mLock) {
IMotor motor = getMotor();
if (mMotorCalibrating || motor == null)
return;
try {
mMotorCalibrating = true;
motor.calibration();
} catch (RemoteException e) {
// Do nothing
}
}
}
private void showCalibrationResult(int status) {
mHandler.post(() -> {
Toast.makeText(PopupCameraService.this,
status == Constants.MOTOR_STATUS_CALIB_OK
? R.string.popup_camera_calibrate_success
: R.string.popup_camera_calibrate_failed,
Toast.LENGTH_LONG)
.show();
});
}
private void showErrorDialog() {
if (mErrorDialogShowing) {
return;
}
mErrorDialogShowing = true;
goBackHome();
mHandler.post(() -> {
Resources res = getResources();
String cameraState = "-1";
int dialogMessageResId = cameraState.equals(Constants.CLOSE_CAMERA_STATE)
? R.string.popup_camera_takeback_failed_times_calibrate
: R.string.popup_camera_popup_failed_times_calibrate;
AlertDialog alertDialog = new AlertDialog.Builder(this, R.style.SystemAlertDialogTheme)
.setTitle(res.getString(R.string.popup_camera_tip))
.setMessage(res.getString(dialogMessageResId))
.setPositiveButton(
res.getString(R.string.popup_camera_calibrate_now),
(dialog, which) -> {
calibrateMotor();
})
.setNegativeButton(res.getString(android.R.string.cancel), null)
.create();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
alertDialog.setCanceledOnTouchOutside(false);
alertDialog.show();
alertDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
mErrorDialogShowing = false;
}
});
});
}
private void playSoundEffect(String state) {
int soundEffect = Integer.parseInt(mPopupCameraPreferences.getSoundEffect());
if (soundEffect != -1) {
if (state.equals(Constants.CLOSE_CAMERA_STATE)) {
soundEffect++;
}
mSoundPool.play(mSounds[soundEffect], 1.0f, 1.0f, 0, 0, 1.0f);
}
}
public void goBackHome() {
Intent homeIntent = new Intent(Intent.ACTION_MAIN);
homeIntent.addCategory(Intent.CATEGORY_HOME);
homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityAsUser(homeIntent, null, UserHandle.CURRENT);
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2015-2016 The CyanogenMod Project
* 2017 The LineageOS 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 org.lineageos.settings.popupcamera;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class PopupCameraSettingsActivity extends PreferenceActivity {
private static final String TAG_POPUPCAMERA = "popupcamera";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager()
.beginTransaction()
.replace(android.R.id.content, new PopupCameraSettingsFragment(),
TAG_POPUPCAMERA)
.commit();
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2018 The LineageOS 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 org.lineageos.settings.popupcamera;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceChangeListener;
import androidx.preference.PreferenceFragment;
import org.lineageos.settings.R;
public class PopupCameraSettingsFragment
extends PreferenceFragment implements OnPreferenceChangeListener {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.popup_settings);
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
return false;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
getActivity().onBackPressed();
return true;
}
return false;
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2019 The LineageOS 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 org.lineageos.settings.popupcamera;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.util.Log;
public class PopupCameraUtils {
private static final String TAG = "PopupCameraUtils";
private static final boolean DEBUG = false;
private static final boolean isPopUpMotorAvailable() {
return PopupCameraService.getMotorService() != null;
}
protected static void startService(Context context) {
if (DEBUG) Log.d(TAG, "Starting service");
context.startServiceAsUser(new Intent(context, PopupCameraService.class),
UserHandle.CURRENT);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(
new ComponentName(context, PopupCameraSettingsActivity.class),
pm.COMPONENT_ENABLED_STATE_ENABLED, pm.SYNCHRONOUS);
}
protected static void stopService(Context context) {
if (DEBUG) Log.d(TAG, "Stopping service");
context.stopServiceAsUser(new Intent(context, PopupCameraService.class),
UserHandle.CURRENT);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(
new ComponentName(context, PopupCameraSettingsActivity.class),
pm.COMPONENT_ENABLED_STATE_DEFAULT, pm.SYNCHRONOUS);
}
public static void checkPopupCameraService(Context context) {
if (isPopUpMotorAvailable()) {
startService(context);
} else {
stopService(context);
}
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-2020 The LineageOS 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 org.lineageos.settings.sensors;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.SystemClock;
import android.util.Log;
import org.lineageos.settings.doze.DozeUtils;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class PickupSensor implements SensorEventListener {
private static final boolean DEBUG = false;
private static final String TAG = "PickupSensor";
private static final int MIN_PULSE_INTERVAL_MS = 2500;
private SensorManager mSensorManager;
private Sensor mSensor;
private Context mContext;
private ExecutorService mExecutorService;
private long mEntryTimestamp;
public PickupSensor(Context context) {
mContext = context;
mSensorManager = mContext.getSystemService(SensorManager.class);
mSensor = SensorsUtils.getSensor(mSensorManager, "xiaomi.sensor.pickup");
mExecutorService = Executors.newSingleThreadExecutor();
}
private Future<?> submit(Runnable runnable) {
return mExecutorService.submit(runnable);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (DEBUG) Log.d(TAG, "Got sensor event: " + event.values[0]);
long delta = SystemClock.elapsedRealtime() - mEntryTimestamp;
if (delta < MIN_PULSE_INTERVAL_MS) {
return;
}
mEntryTimestamp = SystemClock.elapsedRealtime();
if (event.values[0] == 1) {
DozeUtils.launchDozePulse(mContext);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
/* Empty */
}
public void enable() {
if (DEBUG) Log.d(TAG, "Enabling");
submit(() -> {
mSensorManager.registerListener(this, mSensor,
SensorManager.SENSOR_DELAY_NORMAL);
mEntryTimestamp = SystemClock.elapsedRealtime();
});
}
public void disable() {
if (DEBUG) Log.d(TAG, "Disabling");
submit(() -> {
mSensorManager.unregisterListener(this, mSensor);
});
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-2018 The LineageOS 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 org.lineageos.settings.sensors;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
import org.lineageos.settings.doze.DozeUtils;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ProximitySensor implements SensorEventListener {
private static final boolean DEBUG = false;
private static final String TAG = "ProximitySensor";
// Maximum time for the hand to cover the sensor: 1s
private static final int HANDWAVE_MAX_DELTA_NS = 1000 * 1000 * 1000;
// Minimum time until the device is considered to have been in the pocket: 2s
private static final int POCKET_MIN_DELTA_NS = 2000 * 1000 * 1000;
private boolean mSawNear = false;
private SensorManager mSensorManager;
private Sensor mSensor;
private Context mContext;
private ExecutorService mExecutorService;
private long mInPocketTime = 0;
public ProximitySensor(Context context) {
mContext = context;
mSensorManager = mContext.getSystemService(SensorManager.class);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY, false);
mExecutorService = Executors.newSingleThreadExecutor();
}
private Future<?> submit(Runnable runnable) {
return mExecutorService.submit(runnable);
}
@Override
public void onSensorChanged(SensorEvent event) {
boolean isNear = event.values[0] < mSensor.getMaximumRange();
if (mSawNear && !isNear) {
if (shouldPulse(event.timestamp)) {
DozeUtils.launchDozePulse(mContext);
}
} else {
mInPocketTime = event.timestamp;
}
mSawNear = isNear;
}
private boolean shouldPulse(long timestamp) {
long delta = timestamp - mInPocketTime;
if (DozeUtils.isHandwaveGestureEnabled(mContext) &&
DozeUtils.isPocketGestureEnabled(mContext)) {
return true;
} else if (DozeUtils.isHandwaveGestureEnabled(mContext)) {
return delta < HANDWAVE_MAX_DELTA_NS;
} else if (DozeUtils.isPocketGestureEnabled(mContext)) {
return delta >= POCKET_MIN_DELTA_NS;
}
return false;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
/* Empty */
}
public void enable() {
if (DEBUG) Log.d(TAG, "Enabling");
submit(() -> {
mSensorManager.registerListener(this, mSensor,
SensorManager.SENSOR_DELAY_NORMAL);
});
}
public void disable() {
if (DEBUG) Log.d(TAG, "Disabling");
submit(() -> {
mSensorManager.unregisterListener(this, mSensor);
});
}
public boolean getSawNear() {
return mSawNear;
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2020 The LineageOS 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 org.lineageos.settings.sensors;
import android.hardware.Sensor;
import android.hardware.SensorManager;
public final class SensorsUtils {
public static Sensor getSensor(SensorManager sm, String type) {
for (Sensor sensor : sm.getSensorList(Sensor.TYPE_ALL)) {
if (type.equals(sensor.getStringType())) {
return sensor;
}
}
return null;
}
}

View File

@@ -0,0 +1,166 @@
/*
* Copyright (C) 2016 The CyanogenMod 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 org.lineageos.settings.utils;
import android.util.Log;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public final class FileUtils {
private static final String TAG = "FileUtils";
private FileUtils() {
// This class is not supposed to be instantiated
}
/**
* Reads the first line of text from the given file.
* Reference {@link BufferedReader#readLine()} for clarification on what a
* line is
*
* @return the read line contents, or null on failure
*/
public static String readOneLine(String fileName) {
String line = null;
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(fileName), 512);
line = reader.readLine();
} catch (FileNotFoundException e) {
Log.w(TAG, "No such file " + fileName + " for reading", e);
} catch (IOException e) {
Log.e(TAG, "Could not read from file " + fileName, e);
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
// Ignored, not much we can do anyway
}
}
return line;
}
/**
* Writes the given value into the given file
*
* @return true on success, false on failure
*/
public static boolean writeLine(String fileName, String value) {
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(fileName));
writer.write(value);
} catch (FileNotFoundException e) {
Log.w(TAG, "No such file " + fileName + " for writing", e);
return false;
} catch (IOException e) {
Log.e(TAG, "Could not write to file " + fileName, e);
return false;
} finally {
try {
if (writer != null) {
writer.close();
}
} catch (IOException e) {
// Ignored, not much we can do anyway
}
}
return true;
}
/**
* Checks whether the given file exists
*
* @return true if exists, false if not
*/
public static boolean fileExists(String fileName) {
final File file = new File(fileName);
return file.exists();
}
/**
* Checks whether the given file is readable
*
* @return true if readable, false if not
*/
public static boolean isFileReadable(String fileName) {
final File file = new File(fileName);
return file.exists() && file.canRead();
}
/**
* Checks whether the given file is writable
*
* @return true if writable, false if not
*/
public static boolean isFileWritable(String fileName) {
final File file = new File(fileName);
return file.exists() && file.canWrite();
}
/**
* Deletes an existing file
*
* @return true if the delete was successful, false if not
*/
public static boolean delete(String fileName) {
final File file = new File(fileName);
boolean ok = false;
try {
ok = file.delete();
} catch (SecurityException e) {
Log.w(TAG, "SecurityException trying to delete " + fileName, e);
}
return ok;
}
/**
* Renames an existing file
*
* @return true if the rename was successful, false if not
*/
public static boolean rename(String srcPath, String dstPath) {
final File srcFile = new File(srcPath);
final File dstFile = new File(dstPath);
boolean ok = false;
try {
ok = srcFile.renameTo(dstFile);
} catch (SecurityException e) {
Log.w(TAG,
"SecurityException trying to rename " + srcPath + " to " + dstPath,
e);
} catch (NullPointerException e) {
Log.e(TAG,
"NullPointerException trying to rename " + srcPath + " to " +
dstPath,
e);
}
return ok;
}
}