msm8953-common: Initial Common tree

* based on motorola sdm632-common

Co-authored-by: Jorg3Lucas <jorgelucas@pixelexperience.org>
This commit is contained in:
jeangraff30
2020-09-06 15:31:00 +02:00
commit 1220e128cd
154 changed files with 23679 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
/*
* 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 com.moto.actions;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class ActionsPreferenceActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true);
}
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new ActionsPreferenceFragment()).commit();
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2015-2016 The CyanogenMod Project
* Copyright (C) 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 com.moto.actions;
import android.os.Bundle;
import androidx.preference.PreferenceFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class ActionsPreferenceFragment extends PreferenceFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = LayoutInflater.from(getContext()).inflate(R.layout.actions, container, false);
((ViewGroup) view).addView(super.onCreateView(inflater, container, savedInstanceState));
return view;
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.main_panel);
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.util.Log;
import com.moto.actions.actions.Constants;
import com.moto.actions.ServiceWrapper.LocalBinder;
public class BootCompletedReceiver extends BroadcastReceiver {
static final String TAG = "MotoActions";
final String NAVBAR_SHOWN = "navbar_shown";
private ServiceWrapper mServiceWrapper;
@Override
public void onReceive(final Context context, Intent intent) {
Log.i(TAG, "Booting");
if (intent.getAction() != null && !intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
return;
}
// Restore nodes to saved preference values
for (String pref : Constants.sPrefKeys) {
Constants.writePreference(context, pref);
}
context.startService(new Intent(context, ServiceWrapper.class));
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
LocalBinder binder = (LocalBinder) service;
mServiceWrapper = binder.getService();
mServiceWrapper.start();
}
@Override
public void onServiceDisconnected(ComponentName className) {
mServiceWrapper = null;
}
};
}

View File

@@ -0,0 +1,35 @@
/*
* 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 com.moto.actions;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class DozeSettingsActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setTitle(R.string.ambient_display_title);
}
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new DozeSettingsFragment()).commit();
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 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 com.moto.actions;
import android.os.Bundle;
import androidx.preference.PreferenceFragment;
import android.provider.Settings;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import android.view.MenuItem;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.TextView;
public class DozeSettingsFragment extends PreferenceFragment {
private SwitchPreference mHandwavePreference;
private SwitchPreference mPickupPreference;
private TextView mSwitchBarText;
private Switch mAmbientDisplaySwitch;
private String KEY_GESTURE_HAND_WAVE = "gesture_hand_wave";
private String KEY_GESTURE_PICK_UP = "gesture_pick_up";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = LayoutInflater.from(getContext()).inflate(R.layout.doze, container, false);
((ViewGroup) view).addView(super.onCreateView(inflater, container, savedInstanceState));
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
View switchBar = view.findViewById(R.id.switch_bar);
mAmbientDisplaySwitch = (Switch) switchBar.findViewById(android.R.id.switch_widget);
mAmbientDisplaySwitch.setChecked(MotoActionsSettings.isDozeEnabled(getActivity().getContentResolver()));
mAmbientDisplaySwitch.setOnCheckedChangeListener(mAmbientDisplayPrefListener);
switchBar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mAmbientDisplaySwitch.toggle();
}
});
mSwitchBarText = switchBar.findViewById(R.id.switch_text);
mSwitchBarText.setText(MotoActionsSettings.isDozeEnabled(getActivity().getContentResolver()) ? R.string.switch_bar_on :
R.string.switch_bar_off);
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.doze_panel);
boolean dozeEnabled = MotoActionsSettings.isDozeEnabled(getActivity().getContentResolver());
mHandwavePreference = (SwitchPreference) findPreference(KEY_GESTURE_HAND_WAVE);
mPickupPreference = (SwitchPreference) findPreference(KEY_GESTURE_PICK_UP);
updatePrefs(dozeEnabled);
}
private CompoundButton.OnCheckedChangeListener mAmbientDisplayPrefListener =
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean enable) {
if (enableDoze(enable)) {
updatePrefs(enable);
mSwitchBarText.setText(enable ? R.string.switch_bar_on : R.string.switch_bar_off);
}
}
};
private void updatePrefs(boolean enabled){
mHandwavePreference.setEnabled(enabled);
mPickupPreference.setEnabled(enabled);
}
private boolean enableDoze(boolean enable) {
return Settings.Secure.putInt(getActivity().getContentResolver(),
Settings.Secure.DOZE_ENABLED, enable ? 1 : 0);
}
}

View File

@@ -0,0 +1,37 @@
/*
* 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 com.moto.actions;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class FPGestureSettingsActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setTitle(R.string.fingerprint_gestures_title);
}
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new FPGestureSettingsFragment()).commit();
}
}

View File

@@ -0,0 +1,120 @@
/*
* 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 com.moto.actions;
import android.app.ActionBar;
import android.os.Bundle;
import android.content.Context;
import android.content.SharedPreferences.Editor;
import android.preference.PreferenceManager;
import androidx.preference.PreferenceCategory;
import androidx.preference.SwitchPreference;
import android.hardware.fingerprint.FingerprintManager;
import androidx.preference.PreferenceFragment;
import android.view.MenuItem;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.TextView;
import com.moto.actions.actions.Constants;
import static com.moto.actions.actions.Constants.FP_HOME_KEY;
import static com.moto.actions.actions.Constants.FP_HOME_KEY_OFF;
public class FPGestureSettingsFragment extends PreferenceFragment {
private SwitchPreference mFPScreenOffGesture;
private PreferenceCategory mFPScreenOffCategory;
private PreferenceCategory mFPScreenOnCategory;
private TextView mSwitchBarText;
private Switch mFPGestureSwitch;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = LayoutInflater.from(getContext()).inflate(R.layout.fp_gesture, container, false);
((ViewGroup) view).addView(super.onCreateView(inflater, container, savedInstanceState));
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
View switchBar = view.findViewById(R.id.switch_bar);
mFPGestureSwitch = (Switch) switchBar.findViewById(android.R.id.switch_widget);
mFPGestureSwitch.setChecked(isFPGestureEnabled());
mFPGestureSwitch.setOnCheckedChangeListener(mFPGesturePrefListener);
switchBar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mFPGestureSwitch.toggle();
}
});
mSwitchBarText = switchBar.findViewById(R.id.switch_text);
mSwitchBarText.setText(isFPGestureEnabled() ? R.string.switch_bar_on :
R.string.switch_bar_off);
}
private void updatePrefs(boolean enabled){
Editor prefEditor = PreferenceManager.getDefaultSharedPreferences(getActivity()).edit();
prefEditor.putBoolean(FP_HOME_KEY, enabled);
prefEditor.apply();
mFPScreenOnCategory.setEnabled(enabled);
mFPScreenOffGesture.setEnabled(enabled);
mFPScreenOffCategory.setEnabled(enabled);
if(enabled){
boolean hasEnrolledFingerprints = hasEnrolledFingerprints();
mFPScreenOffGesture.setEnabled(!hasEnrolledFingerprints);
mFPScreenOffCategory.setEnabled(!hasEnrolledFingerprints);
}
}
private boolean isFPGestureEnabled(){
return Constants.isPreferenceEnabled(getActivity(), FP_HOME_KEY);
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.fp_gesture_panel);
mFPScreenOffGesture = (SwitchPreference) findPreference(FP_HOME_KEY_OFF);
mFPScreenOffCategory = (PreferenceCategory) findPreference("fp_keys_scr_off");
mFPScreenOnCategory = (PreferenceCategory) findPreference("fp_keys_scr_on");
updatePrefs(isFPGestureEnabled());
}
private CompoundButton.OnCheckedChangeListener mFPGesturePrefListener =
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean enable) {
updatePrefs(enable);
mSwitchBarText.setText(enable ? R.string.switch_bar_on : R.string.switch_bar_off);
}
};
private boolean hasEnrolledFingerprints(){
FingerprintManager fingerprintManager = (FingerprintManager) getActivity().getSystemService(Context.FINGERPRINT_SERVICE);
return fingerprintManager.hasEnrolledFingerprints();
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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 com.moto.actions;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class GestureSettingsActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true);
}
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new GestureSettingsFragment()).commit();
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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 com.moto.actions;
import android.os.Bundle;
import androidx.preference.PreferenceFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class GestureSettingsFragment extends PreferenceFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = LayoutInflater.from(getContext()).inflate(R.layout.gesture, container, false);
((ViewGroup) view).addView(super.onCreateView(inflater, container, savedInstanceState));
return view;
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.actions_panel);
}
}

View File

@@ -0,0 +1,756 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* Copyright (C) 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 com.moto.actions;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ISearchManager;
import android.app.KeyguardManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.hardware.input.InputManager;
import android.media.AudioAttributes;
import android.media.session.MediaSessionLegacyHelper;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.MediaStore;
import android.provider.Settings;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.ViewConfiguration;
import com.android.internal.os.DeviceKeyHandler;
import com.android.internal.util.ArrayUtils;
import com.moto.actions.util.FileUtils;
import java.util.List;
import static com.moto.actions.actions.Constants.*;
public class KeyHandler implements DeviceKeyHandler {
private static final String TAG = KeyHandler.class.getSimpleName();
private static final int GESTURE_REQUEST = 1;
private static final int FP_ACTION_REQUEST = 2;
private static final String ACTION_DISMISS_KEYGUARD =
"com.android.keyguard.action.DISMISS_KEYGUARD_SECURELY";
private static final String GESTURE_WAKEUP_REASON = "keyhandler-gesture-wakeup";
private static final int GESTURE_WAKELOCK_DURATION = 3000;
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
private final Context mContext;
private final PowerManager mPowerManager;
WakeLock mGestureWakeLock;
private KeyguardManager mKeyguardManager;
private FPScreenOffGesturesHandler mFPScreenOffGesturesHandler;
private CameraManager mCameraManager;
private String mRearCameraId;
private boolean mTorchEnabled;
private Vibrator mVibrator;
private ISearchManager mSearchManagerService;
private Handler mHandler;
private int fpTapCounts = 0;
private boolean fpTapPending = false;
private boolean fpGesturePending = false;
private Runnable doubleTapRunnable = new Runnable() {
public void run() {
int action = 0;
if (fpTapCounts > 1) {
action = str2int(FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEY_DBLTAP_NODE)));
} else {
if (isSingleTapEnabledOnFP()) {
action = str2int(FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEYS_NODE)));
}
}
if (action != 0) {
boolean isActionSupported = ArrayUtils.contains(mPowerManager.isScreenOn() ? sFPSupportedActions : sFPSupportedActionsScreenOff, action);
if (isActionSupported) {
fireFPAction(action, true);
}
}
resetDoubleTapOnFP();
}
};
private Runnable fpGestureRunnable = new Runnable() {
public void run() {
resetFPGestureDelay();
}
};
public KeyHandler(Context context) {
mContext = context;
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mFPScreenOffGesturesHandler = new FPScreenOffGesturesHandler();
mGestureWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"GestureWakeLock");
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
if (mVibrator == null || !mVibrator.hasVibrator()) {
mVibrator = null;
}
mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
mCameraManager.registerTorchCallback(new MyTorchCallback(), null);
mHandler = new Handler(Looper.getMainLooper());
}
static long[] getLongIntArray(Resources r, int resid) {
int[] ar = r.getIntArray(resid);
if (ar == null) {
return null;
}
long[] out = new long[ar.length];
for (int i = 0; i < ar.length; i++) {
out[i] = ar[i];
}
return out;
}
private static ActivityInfo getRunningActivityInfo(Context context) {
final ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
final PackageManager pm = context.getPackageManager();
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
if (tasks != null && !tasks.isEmpty()) {
ActivityManager.RunningTaskInfo top = tasks.get(0);
try {
return pm.getActivityInfo(top.topActivity, 0);
} catch (PackageManager.NameNotFoundException e) {
}
}
return null;
}
private static void dispatchMediaKeyWithWakeLock(int keycode, Context context) {
if (ActivityManagerNative.isSystemReady()) {
KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), KeyEvent.ACTION_DOWN, keycode, 0);
MediaSessionLegacyHelper.getHelper(context).sendMediaButtonEvent(event, true);
event = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
MediaSessionLegacyHelper.getHelper(context).sendMediaButtonEvent(event, true);
}
}
private static void switchToLastApp(Context context) {
final ActivityManager am =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.RunningTaskInfo lastTask = getLastTask(context, am);
if (lastTask != null) {
am.moveTaskToFront(lastTask.id, ActivityManager.MOVE_TASK_NO_USER_ACTION);
}
}
private static ActivityManager.RunningTaskInfo getLastTask(Context context,
final ActivityManager am) {
final String defaultHomePackage = resolveCurrentLauncherPackage(context);
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(5);
for (int i = 1; i < tasks.size(); i++) {
String packageName = tasks.get(i).topActivity.getPackageName();
if (!packageName.equals(defaultHomePackage)
&& !packageName.equals(context.getPackageName())
&& !packageName.equals("com.android.systemui")) {
return tasks.get(i);
}
}
return null;
}
private static String resolveCurrentLauncherPackage(Context context) {
final Intent launcherIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME);
final PackageManager pm = context.getPackageManager();
final ResolveInfo launcherInfo = pm.resolveActivity(launcherIntent, 0);
return launcherInfo.activityInfo.packageName;
}
private String getRearCameraId() {
if (mRearCameraId == null) {
try {
for (final String cameraId : mCameraManager.getCameraIdList()) {
CameraCharacteristics characteristics =
mCameraManager.getCameraCharacteristics(cameraId);
int cOrientation = characteristics.get(CameraCharacteristics.LENS_FACING);
if (cOrientation == CameraCharacteristics.LENS_FACING_BACK) {
mRearCameraId = cameraId;
break;
}
}
} catch (CameraAccessException e) {
// Ignore
}
}
return mRearCameraId;
}
private Intent getLaunchableIntent(Intent intent) {
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> resInfo = pm.queryIntentActivities(intent, 0);
if (resInfo.isEmpty()) {
return null;
}
return pm.getLaunchIntentForPackage(resInfo.get(0).activityInfo.packageName);
}
private void triggerCameraAction() {
ensureKeyguardManager();
WakeLock wl = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "GestureWakeLock");
wl.acquire(500);
if (mKeyguardManager.inKeyguardRestrictedInputMode()) {
launchSecureCamera();
} else {
launchCamera();
}
}
private void launchCamera() {
Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
if (getBestActivityInfo(intent) != null) {
// Only launch if we can succeed, but let the user pick the action
mContext.startActivity(intent);
}
}
private void launchSecureCamera() {
// Keyguard won't allow a picker, try to pick the secure intent in the package
// that would be the one used for a default action of launching the camera
Intent normalIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
normalIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
normalIntent.addFlags(Intent.FLAG_FROM_BACKGROUND);
Intent secureIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
secureIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
secureIntent.addFlags(Intent.FLAG_FROM_BACKGROUND);
ActivityInfo normalActivity = getBestActivityInfo(normalIntent);
ActivityInfo secureActivity = getBestActivityInfo(secureIntent, normalActivity);
if (secureActivity != null) {
secureIntent.setComponent(new ComponentName(secureActivity.applicationInfo.packageName, secureActivity.name));
mContext.startActivity(secureIntent);
}
}
private ActivityInfo getBestActivityInfo(Intent intent) {
PackageManager pm = mContext.getPackageManager();
ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
if (resolveInfo != null) {
return resolveInfo.activityInfo;
} else {
// If the resolving failed, just find our own best match
return getBestActivityInfo(intent, null);
}
}
private ActivityInfo getBestActivityInfo(Intent intent, ActivityInfo match) {
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
ActivityInfo best = null;
if (activities.size() > 0) {
best = activities.get(0).activityInfo;
if (match != null) {
String packageName = match.applicationInfo.packageName;
for (int i = activities.size() - 1; i >= 0; i--) {
ActivityInfo activityInfo = activities.get(i).activityInfo;
if (packageName.equals(activityInfo.applicationInfo.packageName)) {
best = activityInfo;
}
}
}
}
return best;
}
private void openBrowser() {
mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
mPowerManager.wakeUp(SystemClock.uptimeMillis(), GESTURE_WAKEUP_REASON);
final Intent intent = getLaunchableIntent(
new Intent(Intent.ACTION_VIEW, Uri.parse("http:")));
startActivitySafely(intent);
}
private void openDialer() {
mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
mPowerManager.wakeUp(SystemClock.uptimeMillis(), GESTURE_WAKEUP_REASON);
final Intent intent = new Intent(Intent.ACTION_DIAL, null);
startActivitySafely(intent);
}
private void openEmail() {
mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
mPowerManager.wakeUp(SystemClock.uptimeMillis(), GESTURE_WAKEUP_REASON);
final Intent intent = getLaunchableIntent(
new Intent(Intent.ACTION_VIEW, Uri.parse("mailto:")));
startActivitySafely(intent);
}
private void openMessages() {
mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
mPowerManager.wakeUp(SystemClock.uptimeMillis(), GESTURE_WAKEUP_REASON);
final String defaultApplication = Settings.Secure.getString(
mContext.getContentResolver(), "sms_default_application");
final PackageManager pm = mContext.getPackageManager();
final Intent intent = pm.getLaunchIntentForPackage(defaultApplication);
if (intent != null) {
startActivitySafely(intent);
}
}
private void toggleFlashlight() {
String rearCameraId = getRearCameraId();
if (rearCameraId != null) {
mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
try {
mCameraManager.setTorchMode(rearCameraId, !mTorchEnabled);
mTorchEnabled = !mTorchEnabled;
} catch (CameraAccessException e) {
// Ignore
}
}
}
private void ensureKeyguardManager() {
if (mKeyguardManager == null) {
mKeyguardManager =
(KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
}
}
private void resetDoubleTapOnFP() {
fpTapCounts = 0;
fpTapPending = false;
mHandler.removeCallbacks(doubleTapRunnable);
}
private void detectDoubleTapOnFP() {
fpTapCounts++;
if (fpTapCounts == 1 || fpTapCounts == 2) {
doHapticFeedbackFP(false);
}
if (!fpTapPending) {
fpTapPending = true;
mHandler.postDelayed(doubleTapRunnable, ViewConfiguration.getDoubleTapTimeout());
}
}
private boolean isSingleTapEnabledOnFP() {
return !FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEYS_NODE)).equals("0");
}
private boolean isDoubleTapEnabledOnFP() {
return !FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEY_DBLTAP_NODE)).equals("0");
}
private boolean isHapticFeedbackEnabledOnFP() {
return !FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_HAPTIC_NODE)).equals("0");
}
private String getFPNodeBasedOnScreenState(String node) {
if (mPowerManager.isScreenOn()) {
return node;
}
switch (node) {
case FP_KEYS_NODE:
return FP_KEYS_SCREENOFF_NODE;
case FP_HAPTIC_NODE:
return FP_HAPTIC_SCREENOFF_NODE;
case FP_KEY_DBLTAP_NODE:
return FP_KEY_SCREENOFF_DBLTAP_NODE;
case FP_KEY_HOLD_NODE:
return FP_KEY_SCREENOFF_HOLD_NODE;
case FP_KEY_RIGHT_NODE:
return FP_KEY_SCREENOFF_RIGHT_NODE;
case FP_KEY_LEFT_NODE:
return FP_KEY_SCREENOFF_LEFT_NODE;
}
return node;
}
public KeyEvent handleKeyEvent(KeyEvent event) {
int scanCode = event.getScanCode();
if (DEBUG) {
Log.d(TAG, "DEBUG: action=" + event.getAction()
+ ", flags=" + event.getFlags()
+ ", keyCode=" + event.getKeyCode()
+ ", scanCode=" + event.getScanCode()
+ ", metaState=" + event.getMetaState()
+ ", repeatCount=" + event.getRepeatCount());
}
boolean isFPScanCode = ArrayUtils.contains(sSupportedFPGestures, scanCode);
if (!isFPScanCode) {
return event;
}
boolean isFPGestureEnabled = FileUtils.readOneLine(FP_HOME_NODE).equals("1");
boolean isFPGestureEnabledOnScreenOff = FileUtils.readOneLine(FP_HOME_OFF_NODE).equals("1");
boolean isScreenOn = mPowerManager.isScreenOn();
// We only want ACTION_UP event
if (event.getAction() != KeyEvent.ACTION_UP) {
return null;
}
if (isFPScanCode){
if (fpGesturePending) {
return event;
} else {
resetFPGestureDelay();
fpGesturePending = true;
mHandler.postDelayed(fpGestureRunnable, 10);
}
}
if (scanCode != FP_TAP_SCANCODE) {
resetDoubleTapOnFP();
}
if (isFPScanCode) {
if ((!isFPGestureEnabled) || (!isScreenOn && !isFPGestureEnabledOnScreenOff)) {
resetDoubleTapOnFP();
return event;
}
if (!isScreenOn && isFPGestureEnabledOnScreenOff) {
processFPScreenOffScancode(scanCode);
} else {
processFPScancode(scanCode);
}
}
return null;
}
private void processFPScancode(int scanCode) {
int action = 0;
boolean isScreenOn = mPowerManager.isScreenOn();
switch (scanCode) {
case FP_TAP_SCANCODE:
if (isDoubleTapEnabledOnFP()) {
detectDoubleTapOnFP();
return;
} else {
resetDoubleTapOnFP();
action = str2int(FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEYS_NODE)));
}
break;
case FP_HOLD_SCANCODE:
action = str2int(FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEY_HOLD_NODE)));
break;
case FP_RIGHT_SCANCODE:
action = str2int(FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEY_RIGHT_NODE)));
break;
case FP_LEFT_SCANCODE:
action = str2int(FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEY_LEFT_NODE)));
break;
}
boolean isActionSupported = ArrayUtils.contains(isScreenOn ? sFPSupportedActions : sFPSupportedActionsScreenOff, action);
if (isActionSupported) {
fireFPAction(action, false);
}
}
private void fireFPAction(int action, boolean isDoubleTap) {
ensureKeyguardManager();
boolean isHapticFeedbackEnabledOnFP = isHapticFeedbackEnabledOnFP();
if (isDoubleTap && action != ACTION_CAMERA && action != ACTION_FLASHLIGHT) {
isHapticFeedbackEnabledOnFP = false;
}
if (isHapticFeedbackEnabledOnFP){
if (action == ACTION_CAMERA || action == ACTION_FLASHLIGHT) {
vibrate(action == ACTION_CAMERA ? 500 : 250);
}else if (action != ACTION_VOICE_ASSISTANT) {
doHapticFeedbackFP(false);
}
}
switch (action) {
case ACTION_HOME:
if (!mKeyguardManager.inKeyguardRestrictedInputMode()) {
triggerVirtualKeypress(mHandler, KeyEvent.KEYCODE_HOME);
}
break;
case ACTION_POWER:
toggleScreenState();
break;
case ACTION_BACK:
triggerVirtualKeypress(mHandler, KeyEvent.KEYCODE_BACK);
break;
case ACTION_RECENTS:
if (!mKeyguardManager.inKeyguardRestrictedInputMode()) {
triggerVirtualKeypress(mHandler, KeyEvent.KEYCODE_APP_SWITCH);
}
break;
case ACTION_VOLUME_UP:
triggerVirtualKeypress(mHandler, KeyEvent.KEYCODE_VOLUME_UP);
break;
case ACTION_VOLUME_DOWN:
triggerVirtualKeypress(mHandler, KeyEvent.KEYCODE_VOLUME_DOWN);
break;
case ACTION_VOICE_ASSISTANT:
if (!mKeyguardManager.inKeyguardRestrictedInputMode()) {
fireGoogleNowOnTap();
}
return;
case ACTION_PLAY_PAUSE:
dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, mContext);
break;
case ACTION_PREVIOUS_TRACK:
dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_PREVIOUS, mContext);
break;
case ACTION_NEXT_TRACK:
dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_NEXT, mContext);
break;
case ACTION_FLASHLIGHT:
toggleFlashlight();
break;
case ACTION_CAMERA:
triggerCameraAction();
break;
case ACTION_SCREENSHOT:
triggerVirtualKeypress(mHandler, KeyEvent.KEYCODE_SYSRQ);
break;
case ACTION_LAST_APP:
if (!mKeyguardManager.inKeyguardRestrictedInputMode()) {
switchToLastApp(mContext);
}
break;
}
}
private void vibrate(int intensity) {
if (mVibrator == null) {
return;
}
mVibrator.vibrate(intensity);
}
private void toggleScreenState() {
if (mPowerManager.isScreenOn()) {
mPowerManager.goToSleep(SystemClock.uptimeMillis());
} else {
mPowerManager.wakeUp(SystemClock.uptimeMillis());
}
}
private void triggerVirtualKeypress(final Handler handler, final int keyCode) {
final InputManager im = InputManager.getInstance();
long now = SystemClock.uptimeMillis();
final KeyEvent downEvent = new KeyEvent(now, now, KeyEvent.ACTION_DOWN,
keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_FROM_SYSTEM, InputDevice.SOURCE_CLASS_BUTTON);
final KeyEvent upEvent = KeyEvent.changeAction(downEvent,
KeyEvent.ACTION_UP);
// add a small delay to make sure everything behind got focus
handler.postDelayed(new Runnable() {
@Override
public void run() {
im.injectInputEvent(downEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
}, 10);
handler.postDelayed(new Runnable() {
@Override
public void run() {
im.injectInputEvent(upEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
}, 20);
}
private void fireGoogleNowOnTap() {
doHapticFeedbackFP(true);
mSearchManagerService = ISearchManager.Stub.asInterface(ServiceManager.getService(Context.SEARCH_SERVICE));
if (mSearchManagerService != null) {
try {
mSearchManagerService.launchAssist(new Bundle());
} catch (RemoteException e) {
}
}
}
private int str2int(String str) {
if (str == null || str.isEmpty()) {
return 0;
}
try {
return Integer.valueOf(str);
} catch (Exception e) {
return 0;
}
}
private void processFPScreenOffScancode(int scanCode) {
if (!mFPScreenOffGesturesHandler.hasMessages(FP_ACTION_REQUEST)) {
Message msg = mFPScreenOffGesturesHandler.obtainMessage(FP_ACTION_REQUEST);
msg.arg1 = scanCode;
mFPScreenOffGesturesHandler.sendMessage(msg);
}
}
private void resetFPGestureDelay() {
fpGesturePending = false;
mHandler.removeCallbacks(fpGestureRunnable);
}
private void fireScreenOffAction(int action) {
boolean haptic = Settings.System.getInt(mContext.getContentResolver(), KEY_GESTURE_ENABLE_HAPTIC_FEEDBACK, 1) != 0;
if (haptic && (action == ACTION_CAMERA || action == ACTION_FLASHLIGHT)) {
vibrate(action == ACTION_CAMERA ? 500 : 250);
}
if (haptic && action == ACTION_POWER){
doHapticFeedbackScreenOff();
}
switch (action) {
case ACTION_POWER:
toggleScreenState();
break;
case ACTION_PLAY_PAUSE:
dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, mContext);
break;
case ACTION_PREVIOUS_TRACK:
dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_PREVIOUS, mContext);
break;
case ACTION_NEXT_TRACK:
dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_NEXT, mContext);
break;
case ACTION_FLASHLIGHT:
toggleFlashlight();
break;
case ACTION_CAMERA:
triggerCameraAction();
break;
case ACTION_BROWSER:
openBrowser();
break;
case ACTION_DIALER:
openDialer();
break;
case ACTION_EMAIL:
openEmail();
break;
case ACTION_MESSAGES:
openMessages();
break;
}
if (action != ACTION_FLASHLIGHT && action != ACTION_CAMERA && action != ACTION_POWER) {
doHapticFeedbackScreenOff();
}
}
private void startActivitySafely(Intent intent) {
intent.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
UserHandle user = new UserHandle(UserHandle.USER_CURRENT);
mContext.startActivityAsUser(intent, null, user);
} catch (ActivityNotFoundException e) {
// Ignore
}
}
private void doHapticFeedbackScreenOff() {
if (mVibrator == null) {
return;
}
boolean enabled = Settings.System.getInt(mContext.getContentResolver(), KEY_GESTURE_ENABLE_HAPTIC_FEEDBACK, 1) != 0;
if (enabled) {
mVibrator.vibrate(50);
}
}
private void doHapticFeedbackFP(boolean longpress) {
if (mVibrator == null) {
return;
}
if (isHapticFeedbackEnabledOnFP()) {
mHandler.post(new Runnable() {
public void run() {
int owningUid;
String owningPackage;
owningUid = android.os.Process.myUid();
owningPackage = mContext.getOpPackageName();
VibrationEffect effect = VibrationEffect.createOneShot(longpress ? 50 : 40, VibrationEffect.DEFAULT_AMPLITUDE);
mVibrator.vibrate(owningUid, owningPackage, effect, null, VIBRATION_ATTRIBUTES);
}
});
}
}
private class FPScreenOffGesturesHandler extends Handler {
@Override
public void handleMessage(Message msg) {
processFPScancode(msg.arg1);
}
}
private class MyTorchCallback extends CameraManager.TorchCallback {
@Override
public void onTorchModeChanged(String cameraId, boolean enabled) {
if (!cameraId.equals(mRearCameraId))
return;
mTorchEnabled = enabled;
}
@Override
public void onTorchModeUnavailable(String cameraId) {
if (!cameraId.equals(mRearCameraId))
return;
mTorchEnabled = false;
}
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.provider.SearchIndexableResource;
import android.provider.SearchIndexablesProvider;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_CLASS_NAME;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_ICON_RESID;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_ACTION;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RANK;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RESID;
import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS;
import static android.provider.SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS;
public class MotoActionsSearchIndexablesProvider extends SearchIndexablesProvider {
private static final String TAG = "MotoActionsSearchIndexablesProvider";
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor queryXmlResources(String[] projection) {
MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);
cursor.addRow(generateResourceRef(new SearchIndexableResource(1, R.xml.actions_panel,
GestureSettingsActivity.class.getName(),
R.drawable.ic_settings_gestures)));
cursor.addRow(generateResourceRef(new SearchIndexableResource(1, R.xml.fp_gesture_panel,
FPGestureSettingsActivity.class.getName(),
R.drawable.ic_settings_fingerprint)));
cursor.addRow(generateResourceRef(new SearchIndexableResource(1, R.xml.fp_gesture_panel_indexable,
FPGestureSettingsActivity.class.getName(),
R.drawable.ic_settings_fingerprint)));
cursor.addRow(generateResourceRef(new SearchIndexableResource(1, R.xml.doze_panel,
DozeSettingsActivity.class.getName(),
R.drawable.ic_settings_doze)));
cursor.addRow(generateResourceRef(new SearchIndexableResource(1, R.xml.doze_panel_indexable,
DozeSettingsActivity.class.getName(),
R.drawable.ic_settings_doze)));
return cursor;
}
private static Object[] generateResourceRef(SearchIndexableResource sir) {
Object[] ref = new Object[7];
ref[COLUMN_INDEX_XML_RES_RANK] = sir.rank;
ref[COLUMN_INDEX_XML_RES_RESID] = sir.xmlResId;
ref[COLUMN_INDEX_XML_RES_CLASS_NAME] = null;
ref[COLUMN_INDEX_XML_RES_ICON_RESID] = sir.iconResId;
ref[COLUMN_INDEX_XML_RES_INTENT_ACTION] = "com.android.settings.action.EXTRA_SETTINGS";
ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE] = "com.moto.actions";
ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS] = sir.className;
return ref;
}
@Override
public Cursor queryRawData(String[] projection) {
MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
return cursor;
}
@Override
public Cursor queryNonIndexableKeys(String[] projection) {
MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS);
return cursor;
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.util.Log;
import java.util.List;
import java.util.LinkedList;
import com.moto.actions.actions.UpdatedStateNotifier;
import com.moto.actions.actions.CameraActivationSensor;
import com.moto.actions.actions.ChopChopSensor;
import com.moto.actions.actions.FlipToMute;
import com.moto.actions.actions.LiftToSilence;
import com.moto.actions.actions.ProximitySilencer;
import com.moto.actions.doze.DozePulseAction;
import com.moto.actions.doze.GlanceSensor;
import com.moto.actions.doze.ProximitySensor;
import com.moto.actions.doze.ScreenReceiver;
import com.moto.actions.doze.ScreenStateNotifier;
public class MotoActionsService extends IntentService implements ScreenStateNotifier,
UpdatedStateNotifier {
private static final String TAG = "MotoActions";
private final PowerManager mPowerManager;
private final PowerManager.WakeLock mWakeLock;
private final List<ScreenStateNotifier> mScreenStateNotifiers = new LinkedList<>();
private final List<UpdatedStateNotifier> mUpdatedStateNotifiers = new LinkedList<>();
public MotoActionsService(Context context) {
super("MotoActionService");
Log.d(TAG, "Starting");
MotoActionsSettings motoActionsSettings = new MotoActionsSettings(context, this);
SensorHelper sensorHelper = new SensorHelper(context);
new ScreenReceiver(context, this);
DozePulseAction mDozePulseAction = new DozePulseAction(context);
mScreenStateNotifiers.add(mDozePulseAction);
// Actionable sensors get screen on/off notifications
mScreenStateNotifiers.add(new GlanceSensor(motoActionsSettings, sensorHelper, mDozePulseAction));
mScreenStateNotifiers.add(new ProximitySensor(motoActionsSettings, sensorHelper, mDozePulseAction));
// Other actions that are always enabled
mUpdatedStateNotifiers.add(new CameraActivationSensor(motoActionsSettings, sensorHelper));
mUpdatedStateNotifiers.add(new ChopChopSensor(motoActionsSettings, sensorHelper));
mUpdatedStateNotifiers.add(new ProximitySilencer(motoActionsSettings, context, sensorHelper));
mUpdatedStateNotifiers.add(new FlipToMute(motoActionsSettings, context, sensorHelper));
mUpdatedStateNotifiers.add(new LiftToSilence(motoActionsSettings, context, sensorHelper));
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
String tag = context.getPackageName() + ":ServiceWakeLock";
mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, tag);
updateState();
}
@Override
protected void onHandleIntent(Intent intent) {
}
@Override
public void screenTurnedOn() {
if (!mWakeLock.isHeld()) {
mWakeLock.acquire();
}
for (ScreenStateNotifier screenStateNotifier : mScreenStateNotifiers) {
screenStateNotifier.screenTurnedOn();
}
}
@Override
public void screenTurnedOff() {
if (mWakeLock.isHeld()) {
mWakeLock.release();
}
for (ScreenStateNotifier screenStateNotifier : mScreenStateNotifiers) {
screenStateNotifier.screenTurnedOff();
}
}
public void updateState() {
if (mPowerManager.isInteractive()) {
screenTurnedOn();
} else {
screenTurnedOff();
}
for (UpdatedStateNotifier notifier : mUpdatedStateNotifiers) {
notifier.updateState();
}
}
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.util.Log;
import com.moto.actions.actions.Constants;
import com.moto.actions.actions.UpdatedStateNotifier;
import com.moto.actions.actions.CameraActivationAction;
import com.moto.actions.actions.TorchAction;
public class MotoActionsSettings implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = "MotoActions";
private static final String GESTURE_CAMERA_ACTION_KEY = "gesture_camera_action";
private static final String GESTURE_CHOP_CHOP_KEY = "gesture_chop_chop";
private static final String GESTURE_PICK_UP_KEY = "gesture_pick_up";
private static final String GESTURE_IR_WAKEUP_KEY = "gesture_hand_wave";
private static final String GESTURE_IR_SILENCER_KEY = "gesture_ir_silencer";
private static final String GESTURE_FLIP_TO_MUTE_KEY = "gesture_flip_to_mute";
private static final String GESTURE_LIFT_TO_SILENCE_KEY = "gesture_lift_to_silence";
private final Context mContext;
private final UpdatedStateNotifier mUpdatedStateNotifier;
private boolean mCameraGestureEnabled;
private boolean mChopChopEnabled;
private boolean mPickUpGestureEnabled;
private boolean mIrWakeUpEnabled;
private boolean mIrSilencerEnabled;
private boolean mFlipToMuteEnabled;
private boolean mLiftToSilenceEnabled;
public MotoActionsSettings(Context context, UpdatedStateNotifier updatedStateNotifier) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
loadPreferences(sharedPrefs);
sharedPrefs.registerOnSharedPreferenceChangeListener(this);
mContext = context;
mUpdatedStateNotifier = updatedStateNotifier;
}
public boolean isCameraGestureEnabled() {
return mCameraGestureEnabled;
}
public boolean isChopChopGestureEnabled() {
return mChopChopEnabled;
}
public static boolean isDozeEnabled(ContentResolver contentResolver) {
return (Settings.Secure.getInt(contentResolver, Settings.Secure.DOZE_ENABLED, 1) != 0);
}
public boolean isDozeEnabled() {
return isDozeEnabled(mContext.getContentResolver());
}
public boolean isIrWakeupEnabled() {
return isDozeEnabled() && mIrWakeUpEnabled;
}
public boolean isPickUpEnabled() {
return isDozeEnabled() && mPickUpGestureEnabled;
}
public boolean isIrSilencerEnabled() {
return mIrSilencerEnabled;
}
public boolean isFlipToMuteEnabled() {
return mFlipToMuteEnabled;
}
public boolean isLiftToSilenceEnabled() {
return mLiftToSilenceEnabled;
}
public void cameraAction() {
new CameraActivationAction(mContext).action();
}
public void chopChopAction() {
new TorchAction(mContext).action();
}
private void loadPreferences(SharedPreferences sharedPreferences) {
mCameraGestureEnabled = sharedPreferences.getBoolean(GESTURE_CAMERA_ACTION_KEY, true);
mChopChopEnabled = sharedPreferences.getBoolean(GESTURE_CHOP_CHOP_KEY, true);
mIrWakeUpEnabled = sharedPreferences.getBoolean(GESTURE_IR_WAKEUP_KEY, false);
mPickUpGestureEnabled = sharedPreferences.getBoolean(GESTURE_PICK_UP_KEY, true);
mIrSilencerEnabled = sharedPreferences.getBoolean(GESTURE_IR_SILENCER_KEY, false);
mFlipToMuteEnabled = sharedPreferences.getBoolean(GESTURE_FLIP_TO_MUTE_KEY, false);
mLiftToSilenceEnabled = sharedPreferences.getBoolean(GESTURE_LIFT_TO_SILENCE_KEY, false);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
boolean updated = true;
if (GESTURE_CAMERA_ACTION_KEY.equals(key)) {
mCameraGestureEnabled = sharedPreferences.getBoolean(GESTURE_CAMERA_ACTION_KEY, true);
} else if (GESTURE_CHOP_CHOP_KEY.equals(key)) {
mChopChopEnabled = sharedPreferences.getBoolean(GESTURE_CHOP_CHOP_KEY, true);
} else if (GESTURE_IR_WAKEUP_KEY.equals(key)) {
mIrWakeUpEnabled = sharedPreferences.getBoolean(GESTURE_IR_WAKEUP_KEY, false);
} else if (GESTURE_PICK_UP_KEY.equals(key)) {
mPickUpGestureEnabled = sharedPreferences.getBoolean(GESTURE_PICK_UP_KEY, true);
} else if (GESTURE_IR_SILENCER_KEY.equals(key)) {
mIrSilencerEnabled = sharedPreferences.getBoolean(GESTURE_IR_SILENCER_KEY, false);
} else if (GESTURE_FLIP_TO_MUTE_KEY.equals(key)) {
mFlipToMuteEnabled = sharedPreferences.getBoolean(GESTURE_FLIP_TO_MUTE_KEY, false);
} else if (GESTURE_LIFT_TO_SILENCE_KEY.equals(key)) {
mLiftToSilenceEnabled = sharedPreferences.getBoolean(GESTURE_LIFT_TO_SILENCE_KEY, false);
} else if (Constants.FP_HOME_KEY.equals(key) || Constants.FP_HAPTIC_KEY.equals(key) || Constants.FP_HOME_KEY_OFF.equals(key) || Constants.FP_HAPTIC_SCREENOFF_KEY.equals(key) || Constants.FP_KEYS.equals(key) || Constants.FP_KEY_DBLTAP.equals(key) || Constants.FP_KEY_HOLD.equals(key) || Constants.FP_KEY_LEFT.equals(key) || Constants.FP_KEY_RIGHT.equals(key)
|| Constants.FP_KEYS_OFF.equals(key) || Constants.FP_KEY_DBLTAP_OFF.equals(key) || Constants.FP_KEY_HOLD_OFF.equals(key) || Constants.FP_KEY_LEFT_OFF.equals(key) || Constants.FP_KEY_RIGHT_OFF.equals(key)) {
Constants.writePreference(mContext, key);
updated = false;
} else {
updated = false;
}
if (updated) {
mUpdatedStateNotifier.updateState();
}
}
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions;
public interface SensorAction {
void action();
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions;
import java.util.List;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
public class SensorHelper {
private static final String TAG = "MotoActions";
private static final int SENSOR_TYPE_MMI_CAMERA_ACTIVATION = 65540;
private static final int SENSOR_TYPE_MMI_CHOP_CHOP = 65546;
private static final int SENSOR_TYPE_MMI_FLAT_UP = 65537;
private static final int SENSOR_TYPE_MMI_FLAT_DOWN = 65538;
private static final int SENSOR_TYPE_MMI_STOW = 65539;
private static final int SENSOR_TYPE_MMI_GLANCE = 65548;
private static final int BATCH_LATENCY_IN_MS = 100;
private final Context mContext;
private final SensorManager mSensorManager;
public SensorHelper(Context context) {
mContext = context;
mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
dumpSensorsList();
}
private void dumpSensorsList() {
try {
FileOutputStream out = mContext.openFileOutput("sensors.txt", Context.MODE_PRIVATE);
OutputStreamWriter writer = new OutputStreamWriter(out);
List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
for (Sensor sensor : sensorList) {
writer.write("sensor " + sensor.getType() + " = " + sensor.getName()
+ " max batch: " + sensor.getFifoMaxEventCount() + " isWakeUp: " + sensor.isWakeUpSensor() + "\n");
}
writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public Sensor getCameraActivationSensor() {
return mSensorManager.getDefaultSensor(SENSOR_TYPE_MMI_CAMERA_ACTIVATION, true);
}
public Sensor getChopChopSensor() {
return mSensorManager.getDefaultSensor(SENSOR_TYPE_MMI_CHOP_CHOP, true);
}
public Sensor getFlatUpSensor() {
return mSensorManager.getDefaultSensor(SENSOR_TYPE_MMI_FLAT_UP, true);
}
public Sensor getFlatDownSensor() {
return mSensorManager.getDefaultSensor(SENSOR_TYPE_MMI_FLAT_DOWN, true);
}
public Sensor getGlanceSensor() {
return mSensorManager.getDefaultSensor(SENSOR_TYPE_MMI_GLANCE, true);
}
public Sensor getProximitySensor() {
return mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY, true);
}
public Sensor getStowSensor() {
return mSensorManager.getDefaultSensor(SENSOR_TYPE_MMI_STOW, true);
}
public void registerListener(Sensor sensor, SensorEventListener listener) {
if (!mSensorManager.registerListener(listener, sensor,
SensorManager.SENSOR_DELAY_NORMAL, BATCH_LATENCY_IN_MS * 1000)) {
throw new RuntimeException("Failed to registerListener for sensor " + sensor);
}
}
public void unregisterListener(SensorEventListener listener) {
mSensorManager.unregisterListener(listener);
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
public class ServiceWrapper extends android.app.Service {
static final String TAG = "MotoActions-ServiceWrapper";
private final IBinder mBinder = new LocalBinder();
private MotoActionsService mMotoActionsService;
public interface ServiceCallback {
void sendResults(int resultCode, Bundle b);
}
public class LocalBinder extends Binder {
ServiceWrapper getService() {
// Return this instance of the service so clients can call public
// methods
return ServiceWrapper.this;
}
}
@Override
public void onCreate() {
Log.i(TAG, "onCreate");
super.onCreate();
mMotoActionsService = new MotoActionsService(this);
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return null;
}
public void setCallback(ServiceCallback callback) {
}
public void start() {
Log.i(TAG, "start");
}
public void stop() {
}
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions.actions;
import android.app.KeyguardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.MediaStore;
import com.moto.actions.SensorAction;
import java.util.List;
public class CameraActivationAction implements SensorAction {
private static final String TAG = "MotoActions";
private static final int TURN_SCREEN_ON_WAKE_LOCK_MS = 500;
private final Context mContext;
private final KeyguardManager mKeyguardManager;
private final PackageManager mPackageManager;
private final PowerManager mPowerManager;
public CameraActivationAction(Context context) {
mContext = context;
mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mPackageManager = context.getPackageManager();
}
@Override
public void action() {
vibrate();
turnScreenOn();
if (mKeyguardManager.isKeyguardLocked()) {
launchSecureCamera();
} else {
launchCamera();
}
}
private void vibrate() {
Vibrator vib = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
if (vib == null) return;
VibrationEffect effect = VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE);
vib.vibrate(effect);
}
private void turnScreenOn() {
String tag = mContext.getPackageName() + ":CameraWakeLock";
WakeLock wl = mPowerManager.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, tag);
wl.acquire(TURN_SCREEN_ON_WAKE_LOCK_MS);
}
private void launchCamera() {
Intent intent = createIntent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
if (getBestActivityInfo(intent) != null) {
// Only launch if we can succeed, but let the user pick the action
mContext.startActivity(intent);
}
}
private void launchSecureCamera() {
// Keyguard won't allow a picker, try to pick the secure intent in the package
// that would be the one used for a default action of launching the camera
Intent normalIntent = createIntent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
Intent secureIntent = createIntent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
ActivityInfo normalActivity = getBestActivityInfo(normalIntent);
ActivityInfo secureActivity = getBestActivityInfo(secureIntent, normalActivity);
if (secureActivity != null) {
secureIntent.setComponent(componentName(secureActivity));
mContext.startActivity(secureIntent);
}
}
private Intent createIntent(String intentName) {
Intent intent = new Intent(intentName);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
return intent;
}
private ActivityInfo getBestActivityInfo(Intent intent) {
ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0);
if (resolveInfo != null) {
return resolveInfo.activityInfo;
} else {
// If the resolving failed, just find our own best match
return getBestActivityInfo(intent, null);
}
}
private ActivityInfo getBestActivityInfo(Intent intent, ActivityInfo match) {
List <ResolveInfo> activities = mPackageManager.queryIntentActivities(intent, 0);
ActivityInfo best = null;
if (activities.size() > 0) {
best = activities.get(0).activityInfo;
if (match != null) {
String packageName = match.applicationInfo.packageName;
for (int i = activities.size()-1; i >= 0; i--) {
ActivityInfo activityInfo = activities.get(i).activityInfo;
if (packageName.equals(activityInfo.applicationInfo.packageName)) {
best = activityInfo;
}
}
}
}
return best;
}
private ComponentName componentName(ActivityInfo activity) {
return new ComponentName(activity.applicationInfo.packageName, activity.name);
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions.actions;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.util.Log;
import com.moto.actions.MotoActionsSettings;
import com.moto.actions.SensorHelper;
public class CameraActivationSensor implements SensorEventListener, UpdatedStateNotifier {
private static final String TAG = "MotoActions-CameraSensor";
private final MotoActionsSettings mMotoActionsSettings;
private boolean mIsEnabled;
public CameraActivationSensor(MotoActionsSettings motoActionsSettings, SensorHelper sensorHelper) {
mMotoActionsSettings = motoActionsSettings;
Sensor sensor = sensorHelper.getCameraActivationSensor();
sensorHelper.registerListener(sensor, this);
}
@Override
public synchronized void updateState() {
if (mMotoActionsSettings.isCameraGestureEnabled() && !mIsEnabled) {
Log.d(TAG, "Enabling");
mIsEnabled = true;
} else if (! mMotoActionsSettings.isCameraGestureEnabled() && mIsEnabled) {
Log.d(TAG, "Disabling");
mIsEnabled = false;
}
}
@Override
public void onSensorChanged(SensorEvent event) {
Log.d(TAG, "activate camera");
if (mIsEnabled) mMotoActionsSettings.cameraAction();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2015-2016 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions.actions;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.util.Log;
import com.moto.actions.MotoActionsSettings;
import com.moto.actions.SensorHelper;
public class ChopChopSensor implements SensorEventListener, UpdatedStateNotifier {
private static final String TAG = "MotoActions-ChopChopSensor";
private final MotoActionsSettings mMotoActionsSettings;
private final SensorHelper mSensorHelper;
private final Sensor mSensor;
private final Sensor mProx;
private boolean mIsEnabled;
private boolean mProxIsCovered;
public ChopChopSensor(MotoActionsSettings motoActionsSettings, SensorHelper sensorHelper) {
mMotoActionsSettings = motoActionsSettings;
mSensorHelper = sensorHelper;
mSensor = sensorHelper.getChopChopSensor();
mProx = sensorHelper.getProximitySensor();
}
@Override
public synchronized void updateState() {
if (mMotoActionsSettings.isChopChopGestureEnabled() && !mIsEnabled) {
Log.d(TAG, "Enabling");
mSensorHelper.registerListener(mSensor, this);
mSensorHelper.registerListener(mProx, mProxListener);
mIsEnabled = true;
} else if (! mMotoActionsSettings.isChopChopGestureEnabled() && mIsEnabled) {
Log.d(TAG, "Disabling");
mSensorHelper.unregisterListener(this);
mSensorHelper.unregisterListener(mProxListener);
mIsEnabled = false;
}
}
@Override
public void onSensorChanged(SensorEvent event) {
Log.d(TAG, "chop chop triggered");
if (mProxIsCovered) {
Log.d(TAG, "proximity sensor covered, ignoring chop-chop");
return;
}
mMotoActionsSettings.chopChopAction();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
private SensorEventListener mProxListener = new SensorEventListener() {
@Override
public synchronized void onSensorChanged(SensorEvent event) {
mProxIsCovered = event.values[0] < mProx.getMaximumRange();
}
@Override
public void onAccuracyChanged(Sensor mSensor, int accuracy) {
}
};
}

View File

@@ -0,0 +1,219 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* Copyright (C) 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 com.moto.actions.actions;
import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import com.moto.actions.util.FileUtils;
public class Constants {
public static final boolean DEBUG = false;
private static final String TAG = "MotoActions";
// FP gestures
public static final int FP_TAP_SCANCODE = 616;
public static final int FP_HOLD_SCANCODE = 617;
public static final int FP_RIGHT_SCANCODE = 620;
public static final int FP_LEFT_SCANCODE = 621;
public static final int[] sSupportedFPGestures = new int[]{
FP_TAP_SCANCODE,
FP_HOLD_SCANCODE,
FP_RIGHT_SCANCODE,
FP_LEFT_SCANCODE
};
// FP actions
public static final int ACTION_HOME = 100;
public static final int ACTION_POWER = 101;
public static final int ACTION_BACK = 102;
public static final int ACTION_RECENTS = 103;
public static final int ACTION_VOLUME_UP = 104;
public static final int ACTION_VOLUME_DOWN = 105;
public static final int ACTION_VOICE_ASSISTANT = 106;
public static final int ACTION_PLAY_PAUSE = 107;
public static final int ACTION_PREVIOUS_TRACK = 108;
public static final int ACTION_NEXT_TRACK = 109;
public static final int ACTION_FLASHLIGHT = 110;
public static final int ACTION_CAMERA = 111;
public static final int ACTION_SCREENSHOT = 112;
public static final int ACTION_BROWSER = 116;
public static final int ACTION_DIALER = 117;
public static final int ACTION_EMAIL = 118;
public static final int ACTION_MESSAGES = 119;
public static final int ACTION_LAST_APP = 121;
public static final int[] sFPSupportedActions = new int[]{
ACTION_HOME,
ACTION_POWER,
ACTION_BACK,
ACTION_RECENTS,
ACTION_VOLUME_UP,
ACTION_VOLUME_DOWN,
ACTION_VOICE_ASSISTANT,
ACTION_PLAY_PAUSE,
ACTION_PREVIOUS_TRACK,
ACTION_NEXT_TRACK,
ACTION_FLASHLIGHT,
ACTION_CAMERA,
ACTION_SCREENSHOT,
ACTION_LAST_APP
};
public static final int[] sFPSupportedActionsScreenOff = new int[]{
ACTION_POWER,
ACTION_VOLUME_UP,
ACTION_VOLUME_DOWN,
ACTION_PLAY_PAUSE,
ACTION_PREVIOUS_TRACK,
ACTION_NEXT_TRACK,
ACTION_FLASHLIGHT,
ACTION_CAMERA
};
// Swap keys
public static final String FP_HOME_KEY = "fp_home";
public static final String FP_HOME_KEY_OFF = "fp_home_scr_off";
// Swap nodes
public static final String FP_HOME_NODE = "/sys/homebutton/enable";
public static final String FP_HOME_OFF_NODE = "/sys/homebutton/enable_off";
// Haptic node
public static final String FP_HAPTIC_NODE = "/sys/homebutton/haptic";
public static final String FP_HAPTIC_KEY = "fp_haptic";
public static final String FP_HAPTIC_SCREENOFF_NODE = "/sys/homebutton/haptic_off";
public static final String FP_HAPTIC_SCREENOFF_KEY = "fp_haptic_scr_off";
// List of keys
public static final String FP_KEYS = "fp_keys";
public static final String FP_KEY_DBLTAP = "fp_key_dbltap";
public static final String FP_KEY_HOLD = "fp_key_hold";
public static final String FP_KEY_LEFT = "fp_key_left";
public static final String FP_KEY_RIGHT = "fp_key_right";
public static final String FP_KEYS_OFF = "fp_keys_off";
public static final String FP_KEY_DBLTAP_OFF = "fp_key_dbltap_off";
public static final String FP_KEY_HOLD_OFF = "fp_key_hold_off";
public static final String FP_KEY_LEFT_OFF = "fp_key_left_off";
public static final String FP_KEY_RIGHT_OFF = "fp_key_right_off";
// Keys nodes
public static final String FP_KEYS_NODE = "/sys/homebutton/key";
public static final String FP_KEY_DBLTAP_NODE = "/sys/homebutton/key_dbltap";
public static final String FP_KEY_HOLD_NODE = "/sys/homebutton/key_hold";
public static final String FP_KEY_LEFT_NODE = "/sys/homebutton/key_left";
public static final String FP_KEY_RIGHT_NODE = "/sys/homebutton/key_right";
public static final String FP_KEYS_SCREENOFF_NODE = "/sys/homebutton/key_screenoff";
public static final String FP_KEY_SCREENOFF_DBLTAP_NODE = "/sys/homebutton/key_screenoff_dbltap";
public static final String FP_KEY_SCREENOFF_HOLD_NODE = "/sys/homebutton/key_screenoff_hold";
public static final String FP_KEY_SCREENOFF_LEFT_NODE = "/sys/homebutton/key_screenoff_left";
public static final String FP_KEY_SCREENOFF_RIGHT_NODE = "/sys/homebutton/key_screenoff_right";
// Screen off gestures haptic
public static final String KEY_GESTURE_ENABLE_HAPTIC_FEEDBACK = "screen_off_gesture_haptic_feedback";
// Holds <preference_key> -> <proc_node> mapping
public static final Map<String, String> sBooleanNodePreferenceMap = new HashMap<>();
// Holds <preference_key> -> <default_values> mapping
public static final Map<String, Object> sNodeDefaultMap = new HashMap<>();
public static final String[] sPrefKeys = {
FP_HOME_KEY,
FP_HOME_KEY_OFF,
FP_HAPTIC_KEY,
FP_HAPTIC_SCREENOFF_KEY,
FP_KEYS,
FP_KEY_DBLTAP,
FP_KEY_HOLD,
FP_KEY_RIGHT,
FP_KEY_LEFT,
FP_KEYS_OFF,
FP_KEY_DBLTAP_OFF,
FP_KEY_HOLD_OFF,
FP_KEY_RIGHT_OFF,
FP_KEY_LEFT_OFF,
FP_HOME_KEY_OFF,
};
static {
sBooleanNodePreferenceMap.put(FP_HOME_KEY, FP_HOME_NODE);
sBooleanNodePreferenceMap.put(FP_HOME_KEY_OFF, FP_HOME_OFF_NODE);
sBooleanNodePreferenceMap.put(FP_HAPTIC_KEY, FP_HAPTIC_NODE);
sBooleanNodePreferenceMap.put(FP_HAPTIC_SCREENOFF_KEY, FP_HAPTIC_SCREENOFF_NODE);
sBooleanNodePreferenceMap.put(FP_KEYS, FP_KEYS_NODE);
sBooleanNodePreferenceMap.put(FP_KEY_DBLTAP, FP_KEY_DBLTAP_NODE);
sBooleanNodePreferenceMap.put(FP_KEY_HOLD, FP_KEY_HOLD_NODE);
sBooleanNodePreferenceMap.put(FP_KEY_LEFT, FP_KEY_LEFT_NODE);
sBooleanNodePreferenceMap.put(FP_KEY_RIGHT, FP_KEY_RIGHT_NODE);
sBooleanNodePreferenceMap.put(FP_KEYS_OFF, FP_KEYS_SCREENOFF_NODE);
sBooleanNodePreferenceMap.put(FP_KEY_DBLTAP_OFF, FP_KEY_SCREENOFF_DBLTAP_NODE);
sBooleanNodePreferenceMap.put(FP_KEY_HOLD_OFF, FP_KEY_SCREENOFF_HOLD_NODE);
sBooleanNodePreferenceMap.put(FP_KEY_LEFT_OFF, FP_KEY_SCREENOFF_LEFT_NODE);
sBooleanNodePreferenceMap.put(FP_KEY_RIGHT_OFF, FP_KEY_SCREENOFF_RIGHT_NODE);
sNodeDefaultMap.put(FP_HOME_KEY, false);
sNodeDefaultMap.put(FP_HOME_KEY_OFF, false);
sNodeDefaultMap.put(FP_HAPTIC_KEY, false);
sNodeDefaultMap.put(FP_HAPTIC_SCREENOFF_KEY, false);
sNodeDefaultMap.put(FP_KEYS, "0");
sNodeDefaultMap.put(FP_KEY_DBLTAP, "0");
sNodeDefaultMap.put(FP_KEY_HOLD, "0");
sNodeDefaultMap.put(FP_KEY_LEFT, "0");
sNodeDefaultMap.put(FP_KEY_RIGHT, "0");
sNodeDefaultMap.put(FP_KEYS_OFF, "0");
sNodeDefaultMap.put(FP_KEY_DBLTAP_OFF, "0");
sNodeDefaultMap.put(FP_KEY_HOLD_OFF, "0");
sNodeDefaultMap.put(FP_KEY_LEFT_OFF, "0");
sNodeDefaultMap.put(FP_KEY_RIGHT_OFF, "0");
}
public static boolean isPreferenceEnabled(Context context, String key) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getBoolean(key, (Boolean) sNodeDefaultMap.get(key));
}
public static String GetPreference(Context context, String key) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getString(key, (String) sNodeDefaultMap.get(key));
}
public static void writePreference(Context context, String pref) {
String value = "1";
if (!pref.equals(FP_KEYS) && !pref.equals(FP_KEY_DBLTAP) && !pref.equals(FP_KEY_HOLD) && !pref.equals(FP_KEY_LEFT) && !pref.equals(FP_KEY_RIGHT) &&
!pref.equals(FP_KEYS_OFF) && !pref.equals(FP_KEY_DBLTAP_OFF) && !pref.equals(FP_KEY_HOLD_OFF) && !pref.equals(FP_KEY_LEFT_OFF) && !pref.equals(FP_KEY_RIGHT_OFF))
value = isPreferenceEnabled(context, pref) ? "1" : "0";
else
value = GetPreference(context, pref);
String node = sBooleanNodePreferenceMap.get(pref);
if (!FileUtils.writeLine(node, value)) {
Log.w(TAG, "Write " + value + " to node " + node +
"failed while restoring saved preference values");
}
}
}

View File

@@ -0,0 +1,146 @@
/*
* Copyright (c) 2016 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions.actions;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.Log;
import com.moto.actions.MotoActionsSettings;
import com.moto.actions.SensorHelper;
public class FlipToMute implements UpdatedStateNotifier {
private static final String TAG = "MotoActions-FlipToMute";
private final NotificationManager mNotificationManager;
private final MotoActionsSettings mMotoActionsSettings;
private final SensorHelper mSensorHelper;
private final Sensor mFlatDown;
private final Sensor mStow;
private boolean canVibrate = false;
private boolean mIsEnabled;
private boolean mIsFlatDown;
private boolean mIsStowed;
private int mFilter;
private Context mContext;
private Receiver mReceiver;
public FlipToMute(MotoActionsSettings motoActionsSettings, Context context,
SensorHelper sensorHelper) {
mMotoActionsSettings = motoActionsSettings;
mContext = context;
mSensorHelper = sensorHelper;
mFlatDown = sensorHelper.getFlatDownSensor();
mStow = sensorHelper.getStowSensor();
mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (mNotificationManager != null) {
mFilter = mNotificationManager.getCurrentInterruptionFilter();
}
mReceiver = new Receiver();
}
@Override
public void updateState() {
if (mMotoActionsSettings.isFlipToMuteEnabled() && !mIsEnabled) {
Log.d(TAG, "Enabling");
mSensorHelper.registerListener(mFlatDown, mFlatDownListener);
mSensorHelper.registerListener(mStow, mStowListener);
mContext.registerReceiver(mReceiver,
new IntentFilter(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED));
mIsEnabled = true;
} else if (!mMotoActionsSettings.isFlipToMuteEnabled() && mIsEnabled) {
Log.d(TAG, "Disabling");
mSensorHelper.unregisterListener(mFlatDownListener);
mSensorHelper.unregisterListener(mStowListener);
mContext.unregisterReceiver(mReceiver);
mIsEnabled = false;
}
}
private SensorEventListener mFlatDownListener = new SensorEventListener() {
@Override
public synchronized void onSensorChanged(SensorEvent event) {
mIsFlatDown = (event.values[0] != 0);
sensorChange();
}
@Override
public void onAccuracyChanged(Sensor mSensor, int accuracy) {
}
};
private SensorEventListener mStowListener = new SensorEventListener() {
@Override
public synchronized void onSensorChanged(SensorEvent event) {
mIsStowed = (event.values[0] != 0);
sensorChange();
}
@Override
public void onAccuracyChanged(Sensor mSensor, int accuracy) {
}
};
private void sensorChange() {
Log.d(TAG, "event: " + mIsFlatDown + " mIsStowed=" + mIsStowed);
if (mIsFlatDown && mIsStowed) {
vibrate();
canVibrate = true;
mNotificationManager.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY);
Log.d(TAG, "Interrupt filter: Allow priority");
} else if (!mIsFlatDown) {
if (canVibrate) {
vibrate();
canVibrate = false;
}
mNotificationManager.setInterruptionFilter(mFilter);
Log.d(TAG, "Interrupt filter: Restore");
}
}
private void vibrate() {
Vibrator vib = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
if (vib == null) return;
VibrationEffect effect = VibrationEffect.createOneShot(250, VibrationEffect.DEFAULT_AMPLITUDE);
vib.vibrate(effect);
}
public class Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (!mIsFlatDown && !mIsStowed) {
if (mNotificationManager == null) return;
mFilter = mNotificationManager.getCurrentInterruptionFilter();
Log.d(TAG, "Interrupt filter: Backup");
}
}
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (c) 2016 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions.actions;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.telephony.PhoneStateListener;
import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import com.moto.actions.MotoActionsSettings;
import com.moto.actions.SensorHelper;
public class LiftToSilence extends PhoneStateListener implements SensorEventListener, UpdatedStateNotifier {
private static final String TAG = "MotoActions-LiftToSilence";
private final MotoActionsSettings mMotoActionsSettings;
private final SensorHelper mSensorHelper;
private final Sensor mFlatUpSensor;
private final Sensor mStowSensor;
private final TelecomManager mTelecomManager;
private final TelephonyManager mTelephonyManager;
private boolean mIsRinging;
private boolean mIsStowed;
private boolean mLastFlatUp;
public LiftToSilence(MotoActionsSettings motoActionsSettings, Context context,
SensorHelper sensorHelper) {
mMotoActionsSettings = motoActionsSettings;
mSensorHelper = sensorHelper;
mFlatUpSensor = sensorHelper.getFlatUpSensor();
mStowSensor = sensorHelper.getStowSensor();
mTelecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
}
@Override
public void updateState() {
if (mMotoActionsSettings.isLiftToSilenceEnabled()) {
mTelephonyManager.listen(this, LISTEN_CALL_STATE);
} else {
mTelephonyManager.listen(this, 0);
}
}
@Override
public synchronized void onCallStateChanged(int state, String incomingNumber) {
if (state == TelephonyManager.CALL_STATE_RINGING && !mIsRinging) {
Log.d(TAG, "Ringing started");
mSensorHelper.registerListener(mFlatUpSensor, this);
mSensorHelper.registerListener(mStowSensor, mStowListener);
mIsRinging = true;
} else if (state != TelephonyManager.CALL_STATE_RINGING && mIsRinging) {
Log.d(TAG, "Ringing stopped");
mSensorHelper.unregisterListener(this);
mSensorHelper.unregisterListener(mStowListener);
mIsRinging = false;
}
}
@Override
public synchronized void onSensorChanged(SensorEvent event) {
boolean thisFlatUp = (event.values[0] != 0);
Log.d(TAG, "event: " + thisFlatUp + " mLastFlatUp=" + mLastFlatUp + " mIsStowed=" +
mIsStowed);
if (mLastFlatUp && !thisFlatUp && !mIsStowed) {
mTelecomManager.silenceRinger();
}
mLastFlatUp = thisFlatUp;
}
@Override
public void onAccuracyChanged(Sensor mSensor, int accuracy) {
}
private SensorEventListener mStowListener = new SensorEventListener() {
@Override
public synchronized void onSensorChanged(SensorEvent event) {
mIsStowed = (event.values[0] != 0);
}
@Override
public void onAccuracyChanged(Sensor mSensor, int accuracy) {
}
};
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions.actions;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.telephony.PhoneStateListener;
import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import com.moto.actions.MotoActionsSettings;
import com.moto.actions.SensorHelper;
import static android.telephony.TelephonyManager.*;
public class ProximitySilencer extends PhoneStateListener implements SensorEventListener, UpdatedStateNotifier {
private static final String TAG = "MotoActions-ProximitySilencer";
private static final int SILENCE_DELAY_MS = 500;
private final TelecomManager mTelecomManager;
private final TelephonyManager mTelephonyManager;
private final MotoActionsSettings mMotoActionsSettings;
private final SensorHelper mSensorHelper;
private final Sensor mSensor;
private boolean mIsRinging;
private long mRingStartedMs;
private boolean mCoveredRinging;
public ProximitySilencer(MotoActionsSettings motoActionsSettings, Context context,
SensorHelper sensorHelper) {
mTelecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
mMotoActionsSettings = motoActionsSettings;
mSensorHelper = sensorHelper;
mSensor = sensorHelper.getProximitySensor();
mCoveredRinging = false;
mIsRinging = false;
}
@Override
public void updateState() {
if (mMotoActionsSettings.isIrSilencerEnabled()) {
mTelephonyManager.listen(this, LISTEN_CALL_STATE);
} else {
mTelephonyManager.listen(this, 0);
}
}
@Override
public synchronized void onSensorChanged(SensorEvent event) {
boolean isNear = event.values[0] < mSensor.getMaximumRange();
long now = System.currentTimeMillis();
if (isNear){
mCoveredRinging = mIsRinging && (now - mRingStartedMs >= SILENCE_DELAY_MS);
return;
}
if (mIsRinging) {
Log.d(TAG, "event: " + event.values[0] + ", " + " covered " + Boolean.toString(mCoveredRinging));
if (mCoveredRinging) {
Log.d(TAG, "Silencing ringer");
mTelecomManager.silenceRinger();
} else {
Log.d(TAG, "Ignoring silence gesture: " + now + " is too close to " +
mRingStartedMs + ", delay=" + SILENCE_DELAY_MS);
}
mCoveredRinging = false;
}
}
@Override
public synchronized void onCallStateChanged(int state, String incomingNumber) {
if (state == CALL_STATE_RINGING && !mIsRinging) {
Log.d(TAG, "Ringing started");
mSensorHelper.registerListener(mSensor, this);
mIsRinging = true;
mRingStartedMs = System.currentTimeMillis();
} else if (state != CALL_STATE_RINGING && mIsRinging) {
Log.d(TAG, "Ringing stopped");
mSensorHelper.unregisterListener(this);
mIsRinging = false;
}
}
@Override
public void onAccuracyChanged(Sensor mSensor, int accuracy) {
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions.actions;
import android.content.Context;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.os.VibrationEffect;
import android.os.Vibrator;
import androidx.annotation.NonNull;
import com.moto.actions.SensorAction;
public class TorchAction implements SensorAction {
private static final String TAG = "MotoActions";
private CameraManager mCameraManager;
private final Vibrator mVibrator;
private String mRearCameraId;
private static boolean mTorchEnabled;
public TorchAction(Context mContext) {
mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
mCameraManager.registerTorchCallback(new MyTorchCallback(), null);
mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
try {
for (final String cameraId : mCameraManager.getCameraIdList()) {
CameraCharacteristics characteristics =
mCameraManager.getCameraCharacteristics(cameraId);
int cOrientation = characteristics.get(CameraCharacteristics.LENS_FACING);
if (cOrientation == CameraCharacteristics.LENS_FACING_BACK) {
mRearCameraId = cameraId;
break;
}
}
} catch (CameraAccessException e) {
// Noop
}
}
@Override
public void action() {
VibrationEffect vibrationEffect = VibrationEffect.createOneShot(250, VibrationEffect.DEFAULT_AMPLITUDE);
mVibrator.vibrate(vibrationEffect);
if (mRearCameraId != null) {
try {
mCameraManager.setTorchMode(mRearCameraId, !mTorchEnabled);
mTorchEnabled = !mTorchEnabled;
} catch (CameraAccessException e) {
// Noop
}
}
}
private class MyTorchCallback extends CameraManager.TorchCallback {
@Override
public void onTorchModeChanged(@NonNull String cameraId, boolean enabled) {
if (!cameraId.equals(mRearCameraId))
return;
mTorchEnabled = enabled;
}
@Override
public void onTorchModeUnavailable(@NonNull String cameraId) {
if (!cameraId.equals(mRearCameraId))
return;
mTorchEnabled = false;
}
}
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions.actions;
public interface UpdatedStateNotifier {
void updateState();
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions.doze;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.moto.actions.SensorAction;
public class DozePulseAction implements SensorAction, ScreenStateNotifier {
private static final String TAG = "MotoActions";
private static final int DELAY_BETWEEN_DOZES_IN_MS = 1500;
private final Context mContext;
private long mLastDoze;
public DozePulseAction(Context context) {
mContext = context;
}
@Override
public void screenTurnedOn() {
}
@Override
public void screenTurnedOff() {
mLastDoze = System.currentTimeMillis();
}
public void action() {
if (mayDoze()) {
Log.d(TAG, "Sending doze.pulse intent");
mContext.sendBroadcast(new Intent("com.android.systemui.doze.pulse"));
}
}
private synchronized boolean mayDoze() {
long now = System.currentTimeMillis();
if (now - mLastDoze > DELAY_BETWEEN_DOZES_IN_MS) {
Log.d(TAG, "Allowing doze");
mLastDoze = now;
return true;
} else {
Log.d(TAG, "Denying doze");
return false;
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 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 com.moto.actions.doze;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.util.Log;
import com.moto.actions.MotoActionsSettings;
import com.moto.actions.SensorAction;
import com.moto.actions.SensorHelper;
public class GlanceSensor implements ScreenStateNotifier {
private static final String TAG = "MotoActions-GlanceSensor";
private final MotoActionsSettings mMotoActionsSettings;
private final SensorHelper mSensorHelper;
private final SensorAction mSensorAction;
private final Sensor mSensor;
private boolean mEnabled;
public GlanceSensor(MotoActionsSettings motoActionsSettings, SensorHelper sensorHelper,
SensorAction action) {
mMotoActionsSettings = motoActionsSettings;
mSensorHelper = sensorHelper;
mSensorAction = action;
mSensor = sensorHelper.getGlanceSensor();
}
@Override
public void screenTurnedOn() {
if (mEnabled) {
Log.d(TAG, "Disabling");
mSensorHelper.unregisterListener(mGlanceListener);
mEnabled = false;
}
}
@Override
public void screenTurnedOff() {
if (mMotoActionsSettings.isPickUpEnabled() && !mEnabled) {
Log.d(TAG, "Enabling");
mSensorHelper.registerListener(mSensor, mGlanceListener);
mEnabled = true;
}
}
private SensorEventListener mGlanceListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
Log.d(TAG, "triggered");
mSensorAction.action();
}
@Override
public void onAccuracyChanged(Sensor mSensor, int accuracy) {
}
};
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions.doze;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.util.Log;
import com.moto.actions.MotoActionsSettings;
import com.moto.actions.SensorAction;
import com.moto.actions.SensorHelper;
public class ProximitySensor implements ScreenStateNotifier, SensorEventListener {
private static final String TAG = "MotoActions-ProximitySensor";
private final MotoActionsSettings mMotoActionsSettings;
private final SensorHelper mSensorHelper;
private final SensorAction mSensorAction;
private final Sensor mSensor;
private boolean mEnabled;
private boolean mSawNear = false;
public ProximitySensor(MotoActionsSettings motoActionsSettings, SensorHelper sensorHelper,
SensorAction action) {
mMotoActionsSettings = motoActionsSettings;
mSensorHelper = sensorHelper;
mSensorAction = action;
mSensor = sensorHelper.getProximitySensor();
}
@Override
public void screenTurnedOn() {
if (mEnabled) {
Log.d(TAG, "Disabling");
mSensorHelper.unregisterListener(this);
mEnabled = false;
}
}
@Override
public void screenTurnedOff() {
if (mMotoActionsSettings.isIrWakeupEnabled() && !mEnabled) {
Log.d(TAG, "Enabling");
mSensorHelper.registerListener(mSensor, this);
mEnabled = true;
}
}
@Override
public void onSensorChanged(SensorEvent event) {
boolean isNear = event.values[0] < mSensor.getMaximumRange();
if (mSawNear && !isNear) {
Log.d(TAG, "wave triggered");
mSensorAction.action();
}
mSawNear = isNear;
}
@Override
public void onAccuracyChanged(Sensor mSensor, int accuracy) {
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions.doze;
import java.util.List;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import com.moto.actions.actions.Constants;
public class ScreenReceiver extends BroadcastReceiver {
private final ScreenStateNotifier mNotifier;
public ScreenReceiver(Context context, ScreenStateNotifier notifier) {
mNotifier = notifier;
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
context.registerReceiver(this, filter);
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() == null) return;
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
mNotifier.screenTurnedOff();
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
mNotifier.screenTurnedOn();
}
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2015 The CyanogenMod Project
* Copyright (c) 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 com.moto.actions.doze;
public interface ScreenStateNotifier {
void screenTurnedOn();
void screenTurnedOff();
}

View File

@@ -0,0 +1,125 @@
/*
* 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 com.moto.actions.util;
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 = "0";
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();
}
}