打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
“翻转静音”的Android实现
“翻转静音”的Android实现

有朋友很想要Symbian系统上来电话时翻转静音的功能,于是帮其实现之。
因其手机为Android1.5版本,所以使用了部分老旧的API,参考时请注意。

要求功能:

设置是否开启翻转静音功能——上图“电话”选项。
设置功能开始状态下在托盘区是否显示图标——上图“托盘图标”选项。
设置触发静音的翻转角度——上图“翻转触发角度”选项,另点击“当前手机角度”可直接将触发角度设为当前手机倾斜角度。

详细见下图:

程序设计:

主体结构

提供用户设置的界面——TurnSilenceActivity
在后台运行,来电话时监视翻转进行静音的服务——TurnSilenceService
接受系统消息,在开机时启动翻转静音服务——TurnSilenceReceiver

主要技术

获知来电话事件——PhoneStateListener
获取手机倾斜角度——TYPE_ACCELEROMETER
改变手机振铃模式——AUDIO_SERVICE
显示托盘图标——NOTIFICATION_SERVICE
保存用户设定——SharedPreferences

详细见下图:

代码实现:

TurnSilenceReceiver.java

public class TurnSilenceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
TurnSilenceResource mTsRes = new TurnSilenceResource(context);
boolean optCallFlg = mTsRes.getOptCallValue();

if (true == optCallFlg) {
TurnSilenceUtility.startService(mTsRes, TurnSilenceService.class,
TurnSilenceActivity.class);
}
}
}

TurnSilenceActivity.java

public class TurnSilenceActivity extends PreferenceActivity implements
OnPreferenceChangeListener, OnPreferenceClickListener {
private SensorManager mSensorMgr;
private Sensor mGravitySensor;
private double mDegreeDbl;
private TurnSilenceResource mTsRes;
private EditTextPreference mOptTriggerDegreeEditTextPref;
private Preference mOptRealDegreePref;

private final SensorEventListener mSensorEventListener = new SensorEventListener() {
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
public void onSensorChanged(SensorEvent event) {
double g = TurnSilenceUtility.GRAVITY;
double degreeDbl;
String degreeStr;
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
degreeDbl = event.values[SensorManager.DATA_Z];
if (g < Math.abs(degreeDbl)) {
g = Math.abs(degreeDbl);
}
degreeDbl = Math.asin(degreeDbl / g);
mDegreeDbl = degreeDbl * TurnSilenceUtility.DEGREE_PI / Math.PI;
degreeStr = String.format(mTsRes.getOptRealDegreeFormat(),
mDegreeDbl);
mOptRealDegreePref.setSummary(degreeStr);
}
}
};

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.layout.options);
mTsRes = new TurnSilenceResource(this);
getPreferenceScreen().findPreference(mTsRes.getOptCallKey())
.setOnPreferenceChangeListener(this);
mOptRealDegreePref = getPreferenceScreen().findPreference(
mTsRes.getOptRealDegreeKey());
mOptRealDegreePref.setOnPreferenceClickListener(this);
mOptTriggerDegreeEditTextPref = (EditTextPreference) getPreferenceScreen()
.findPreference(mTsRes.getOptTriggerDegreeKey());
mOptTriggerDegreeEditTextPref.setOnPreferenceChangeListener(this);
if (true == mTsRes.getOptCallValue()) {
TurnSilenceUtility.startService(mTsRes, TurnSilenceService.class,
TurnSilenceActivity.class);
}
mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mGravitySensor = mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}

@Override
protected void onResume() {
super.onResume();
mSensorMgr.registerListener(mSensorEventListener, mGravitySensor,
SensorManager.SENSOR_DELAY_NORMAL);
}

@Override
protected void onPause() {
mSensorMgr.unregisterListener(mSensorEventListener);
super.onPause();
}

@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String key;
boolean ret = false;
key = preference.getKey();
if (mTsRes.getOptCallKey().equals(key)) {
if (true == mTsRes.getOptCallValue()) {
TurnSilenceUtility
.stopService(mTsRes, TurnSilenceService.class);
} else {
TurnSilenceUtility.startService(mTsRes,
TurnSilenceService.class, TurnSilenceActivity.class);
}
ret = true;
} else if (mTsRes.getOptTriggerDegreeKey().equals(key)) {
try {
Double.parseDouble((String) newValue);
ret = true;
} catch (NumberFormatException e) {
ret = false;
}
}
return ret;
}

@Override
public boolean onPreferenceClick(Preference preference) {
String key = preference.getKey();
if (mTsRes.getOptRealDegreeKey().equals(key)) {
String degreeStr;
degreeStr = Double.toString(mDegreeDbl);
mOptTriggerDegreeEditTextPref.setText(degreeStr);
}
return true;
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.item_about:
startActivity(new Intent(this, TurnSilenceAbout.class));
return true;
case R.id.item_exit:
mSensorMgr.unregisterListener(mSensorEventListener);
finish();
return true;
}
return false;
}
}

TurnSilenceService.java

public class TurnSilenceService extends Service implements
OnSharedPreferenceChangeListener {
private NotificationManager mNotificationMgr;
private TelephonyManager mTelephonyMgr;
private AudioManager mAudioMgr;
private SensorManager mSensorMgr;
private Sensor mGravitySensor;
private boolean mGravitySensorFlg = false;
private boolean mUpwardFlg = false;
private int mRingerMode;
private double mTriggerDegree;
private TurnSilenceResource mTsRes;
private Class<?> mMainClass;

private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onCallStateChanged(final int state,
final String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
if (false == mGravitySensorFlg) {
mRingerMode = mAudioMgr.getRingerMode();
if (AudioManager.RINGER_MODE_SILENT != mRingerMode) {
mSensorMgr.registerListener(mSensorEventListener,
mGravitySensor,
SensorManager.SENSOR_DELAY_NORMAL);
mGravitySensorFlg = true;
}
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
case TelephonyManager.CALL_STATE_IDLE:
if (true == mGravitySensorFlg) {
mSensorMgr.unregisterListener(mSensorEventListener);
mAudioMgr.setRingerMode(mRingerMode);
mGravitySensorFlg = false;
}
break;
default:
break;
}
}
};

private final SensorEventListener mSensorEventListener = new SensorEventListener() {
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}

@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
if (event.values[SensorManager.DATA_Z] >= mTriggerDegree) {
mUpwardFlg = true;
} else {
if (true == mUpwardFlg) {
mAudioMgr
.setRingerMode(AudioManager.RINGER_MODE_SILENT);
mUpwardFlg = false;
}
}
}
}
};

@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public void onCreate() {
super.onCreate();
mTsRes = new TurnSilenceResource(this);
mTsRes.regOnSharedPrefChangeListener(this);
mTriggerDegree = getTriggerDegree();
mTelephonyMgr = (TelephonyManager) this
.getSystemService(Context.TELEPHONY_SERVICE);
mTelephonyMgr.listen(mPhoneStateListener,
PhoneStateListener.LISTEN_CALL_STATE);
mAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mGravitySensor = mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mNotificationMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}

@Override
public void onStart(Intent intent, int startId) {
String str;
str = intent.getExtras().getString(mTsRes.getDataMainClassKey());
try {
mMainClass = Class.forName(str);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (true == mTsRes.getOptTrayValue()) {
showTrayIcon();
}
}

@Override
public void onDestroy() {
if (true == mGravitySensorFlg) {
mSensorMgr.unregisterListener(mSensorEventListener);
mAudioMgr.setRingerMode(mRingerMode);
mGravitySensorFlg = false;
}
mTelephonyMgr.listen(mPhoneStateListener,
PhoneStateListener.LISTEN_NONE);
mTsRes.unregOnSharedPrefChangeListener(this);
if (true == mTsRes.getOptTrayValue()) {
hideTrayIcon();
}
super.onDestroy();
}

@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPref,
String key) {
if (mTsRes.getOptTriggerDegreeKey().equals(key)) {
mTriggerDegree = getTriggerDegree();
if (true == mTsRes.getOptTrayValue()) {
showTrayIcon();
}
} else if (mTsRes.getOptTrayKey().equals(key)) {
if (true == mTsRes.getOptTrayValue()) {
showTrayIcon();
} else {
hideTrayIcon();
}
}
}

private double getTriggerDegree() {
double degreeDbl;
String degreeStr = mTsRes.getOptTriggerDegreeValue();
degreeDbl = Double.parseDouble(degreeStr);
degreeDbl = degreeDbl * Math.PI / TurnSilenceUtility.DEGREE_PI;
degreeDbl = Math.sin(degreeDbl);
degreeDbl = degreeDbl * TurnSilenceUtility.GRAVITY;
return degreeDbl;
}

private void showTrayIcon() {
int trayIconID = 0;
String tickerText = null;
long when = 0L;
Notification notification;
String trayNotificationTitle;
String trayNotificationFormat;
String trayNotificationText;
Intent trayNotificationIntent;
PendingIntent trayNotificationPendingIntent;
double degreeDbl = 0;
String degreeStr = null;
trayNotificationTitle = mTsRes.getOptTrayNotificationTitle();
trayNotificationFormat = mTsRes.getOptTrayNotificationFormat();
degreeStr = mTsRes.getOptTriggerDegreeValue();
degreeDbl = Double.parseDouble(degreeStr);
trayNotificationText = String.format(trayNotificationFormat, degreeDbl);
trayNotificationIntent = new Intent(this, mMainClass);
trayNotificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_NEW_TASK);
trayNotificationPendingIntent = PendingIntent.getActivity(this,
TurnSilenceUtility.NOTIFICATION_ID_TRAY,
trayNotificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
trayIconID = mTsRes.getTrayIconId();
tickerText = mTsRes.getOptTrayTickerText();
when = System.currentTimeMillis();
notification = new Notification(trayIconID, tickerText, when);
notification.flags = Notification.FLAG_ONGOING_EVENT;
notification.setLatestEventInfo(this, trayNotificationTitle,
trayNotificationText, trayNotificationPendingIntent);
mNotificationMgr.notify(TurnSilenceUtility.NOTIFICATION_ID_TRAY,
notification);
return;
}

private void hideTrayIcon() {
mNotificationMgr.cancel(TurnSilenceUtility.NOTIFICATION_ID_TRAY);
return;
}
}

TurnSilenceAbout.java

public class TurnSilenceAbout extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.about);
}
}

TurnSilenceUtility.java

public class TurnSilenceUtility {
public static final double GRAVITY = 9.81;
public static final double DEGREE_PI = 180;
public static final int NOTIFICATION_ID_TRAY = 0;

public static void startService(TurnSilenceResource tsRes, Class<?> destCls,
Class<?> mainCls) {
Context context;
String str = null;
Intent i;
context = tsRes.getAppContext();
i = new Intent(context, destCls);
str = mainCls.getCanonicalName();
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra(tsRes.getDataMainClassKey(), str);
context.startService(i);
}

public static void stopService(TurnSilenceResource tsRes, Class<?> destCls) {
Context context;
Intent i;
context = tsRes.getAppContext();
i = new Intent(context, destCls);
context.stopService(i);
}
}

TurnSilenceResource.java

public class TurnSilenceResource {
private Context mAppContext;
private SharedPreferences mSharedPref;
private String mOptCallKey = null;
private boolean mOptCallDefaultValue = false;
private String mOptRealDegreeKey = null;
private String mOptRealDegreeFormat = null;
private String mOptTriggerDegreeKey = null;
private String mOptTriggerDegreeDefaultValue = null;
private String mOptTrayKey = null;
private boolean mOptTrayDefaultValue = false;
private String mOptTrayTickerText = null;
private String mOptTrayNotificationTitle = null;
private String mOptTrayNotificationFormat = null;
private String mDataMainClassKey = null;
private int mTrayIcon = 0;

public TurnSilenceResource(Context context) {
getStringValue(context);
getResId();
mSharedPref = PreferenceManager.getDefaultSharedPreferences(context);
mAppContext = context;
}

public String getOptCallKey() {
return mOptCallKey;
}

public String getOptRealDegreeKey() {
return mOptRealDegreeKey;
}

public String getOptRealDegreeFormat() {
return mOptRealDegreeFormat;
}

public String getOptTriggerDegreeKey() {
return mOptTriggerDegreeKey;
}

public String getOptTrayKey() {
return mOptTrayKey;
}

public String getOptTrayTickerText() {
return mOptTrayTickerText;
}

public String getOptTrayNotificationTitle() {
return mOptTrayNotificationTitle;
}

public String getOptTrayNotificationFormat() {
return mOptTrayNotificationFormat;
}

public String getDataMainClassKey() {
return mDataMainClassKey;
}

public Context getAppContext() {
return mAppContext;
}

public int getTrayIconId() {
return mTrayIcon;
}

public boolean getOptCallValue() {
return mSharedPref.getBoolean(mOptCallKey, mOptCallDefaultValue);
}

public String getOptTriggerDegreeValue() {
return mSharedPref.getString(mOptTriggerDegreeKey,
mOptTriggerDegreeDefaultValue);
}

public boolean getOptTrayValue() {
return mSharedPref.getBoolean(mOptTrayKey, mOptTrayDefaultValue);
}

public void regOnSharedPrefChangeListener(
OnSharedPreferenceChangeListener listener) {
mSharedPref.registerOnSharedPreferenceChangeListener(listener);
}

public void unregOnSharedPrefChangeListener(
OnSharedPreferenceChangeListener listener) {
mSharedPref.unregisterOnSharedPreferenceChangeListener(listener);
}

private void getStringValue(Context context) {
String str = null;
mOptCallKey = context.getResources().getString(R.string.opt_call_key);
str = context.getResources().getString(R.string.opt_call_default_value);
mOptCallDefaultValue = Boolean.valueOf(str);
mOptRealDegreeKey = context.getResources().getString(
R.string.opt_real_degree_key);
mOptTriggerDegreeKey = context.getResources().getString(
R.string.opt_trigger_degree_key);
mOptTriggerDegreeDefaultValue = context.getResources().getString(
R.string.opt_trigger_degree_default_value);
mOptRealDegreeFormat = context.getResources().getString(
R.string.opt_real_degree_format);
mOptTrayKey = context.getResources().getString(R.string.opt_tray_key);
mOptTrayDefaultValue = false;
str = context.getResources().getString(R.string.opt_tray_default_value);
mOptTrayDefaultValue = Boolean.valueOf(str);
mOptTrayTickerText = context.getResources().getString(
R.string.opt_tray_ticker_text);
mOptTrayNotificationTitle = context.getResources().getString(
R.string.opt_tray_notification_title);
mOptTrayNotificationFormat = context.getResources().getString(
R.string.opt_tray_notification_title);
mOptTrayNotificationFormat = context.getResources().getString(
R.string.opt_tray_notification_format);
mDataMainClassKey = context.getResources().getString(
R.string.data_main_class_key);
}

private void getResId() {
mTrayIcon = R.drawable.icon;
}
}

res/layout/option.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference android:key="@string/opt_call_key"
android:title="@string/opt_call_title" android:summary="@string/opt_call_summary"
android:defaultValue="@string/opt_call_default_value" />
<Preference android:key="@string/opt_real_degree_key"
android:title="@string/opt_real_degree_title" android:summary="@string/opt_real_degree_summary" />
<EditTextPreference android:key="@string/opt_trigger_degree_key"
android:title="@string/opt_trigger_degree_title" android:summary="@string/opt_trigger_degree_summary"
android:dialogTitle="@string/opt_trigger_degree_dialogtitle"
android:defaultValue="@string/opt_trigger_degree_default_value"
android:inputType="numberSigned|numberDecimal" />
<CheckBoxPreference android:key="@string/opt_tray_key"
android:title="@string/opt_tray_title" android:summary="@string/opt_tray_summary"
android:defaultValue="@string/opt_tray_default_value" />
</PreferenceScreen>

res/layout/about.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:padding="10dip">
<TextView android:id="@+id/about_content"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/about_text" />
</ScrollView>

res/menu/menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/item_about" android:title="@string/item_about_label"
android:alphabeticShortcut="@string/item_about_shortcut" />
<item android:id="@+id/item_exit" android:title="@string/item_exit_label"
android:alphabeticShortcut="@string/item_exit_shortcut" />
</menu>

res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, TurnSilence!</string>
<string name="app_name">翻转静音</string>
<string name="opt_call_key">opt_call</string>
<string name="opt_call_title">电话</string>
<string name="opt_call_summary">来电时进行翻转静音</string>
<string name="opt_call_default_value">true</string>
<string name="opt_real_degree_key">opt_real_degree</string>
<string name="opt_real_degree_title">当前手机角度</string>
<string name="opt_real_degree_summary">设置翻转触发角度</string>
<string name="opt_real_degree_format">点击设置翻转触发角度为:%1$.0f°</string>
<string name="opt_trigger_degree_key">opt_trigger_degree</string>
<string name="opt_trigger_degree_title">翻转触发角度</string>
<string name="opt_trigger_degree_dialogtitle">输入角度</string>
<string name="opt_trigger_degree_summary">指定翻转触发角度</string>
<string name="opt_trigger_degree_default_value">-60</string>
<string name="opt_tray_key">opt_tray_key</string>
<string name="opt_tray_title">托盘图标</string>
<string name="opt_tray_summary">服务时显示托盘图标</string>
<string name="opt_tray_default_value">true</string>
<string name="item_about_label">关于</string>
<string name="item_about_shortcut">a</string>
<string name="item_exit_label">退出</string>
<string name="item_exit_shortcut">x</string>
<string name="about_title">About</string>
<string name="about_text">
\
送给我的朋友;)
</string>
<string name="opt_tray_ticker_text">翻转静音启动!</string>
<string name="opt_tray_notification_title">翻转静音</string>
<string name="opt_tray_notification_format">触发角度为:%1$.0f°</string>
<string name="data_main_class_key">data_main_class_key</string>
</resources>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mtyy110.android.turnsilence" android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<receiver android:name=".TurnSilenceReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
<service android:name=".TurnSilenceService">
</service>
<activity android:name=".TurnSilenceActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".TurnSilenceAbout" android:label="@string/about_title"
android:theme="@android:style/Theme.Dialog">
</activity>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>  
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
android如何监听发送短信?
关于Android 自定义Dialog按钮监听和数据传递到Acitivity的实现
实现Android的防火墙和流量统计代码
Android自定义控件实战-PickerVIew
Android 程序自动更新功能模块实现
Android 简易版天气预报app的现实(2)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服