需求:
单独修改gmail和google日历默认铃声,区别于系统的默认通知音
解决方法:
因为GMS包没有源码,所以无法通过修改apk的方法解决,只能修改获取默认铃声时的uri实现。
具体设计到的文件
/base/media/java/android/media/RingtoneManager.java
/base/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
/base/services/core/java/com/android/server/notification/NotificationManagerService.java
/providers/MediaProvider/src/com/android/providers/media/RingtonePickerActivity.java
在RingtoneManager.java中主要定义读取默认铃声uri的方法
/**
* Check the given uri whether exist in device.
*
* @param context the context.
* @param uri the given uri.
* @return if exist return true, otherwise false.
* @hide
* @internal
*/
private static String getNotificationUriByName(Context context, String ringname) {
// TODO Auto-generated method stub
Cursor cursor = context.getContentResolver().query(
MediaStore.Audio.Media.INTERNAL_CONTENT_URI,
new String[] { "_id" }, "_display_name=? and is_notification=1",
new String[] { ringname }, null);
int id = 0;
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
id = cursor.getInt(0);
} while (cursor.moveToNext());
}
}
Uri ringtoneUri = ContentUris.withAppendedId(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, id);
if (cursor != null) {
cursor.close();
}
Log.d(TAG, "getNotificationUriByName ringname = " + ringname + " , ringtoneUri = " + ringtoneUri);
return ringtoneUri + "";
}
/**
* Check the given uri whether exist in device.
*
* @param context the context.
* @param uri the given uri.
* @return if exist return true, otherwise false.
* @hide
* @internal
*/
public static String getNotificationUri(Context context) {
boolean iccid = "1".equals(android.os.SystemProperties.get("persist.operator.subid", "0")) ? true : false; //Iccid ==1, return true;
boolean is_op07 = "OP07".equals(android.os.SystemProperties.get("persist.operator.optr", "")) ? true : false; //op07, return true;
String mccMnc = android.os.SystemProperties.get("persist.bootanim.mnc", ""); //this is enough for W2100, 334050 or 334090...
Log.d(TAG, "LCT dual-perso. iccid = " + iccid + ". is_op07 = " + is_op07 + ". mccMnc = " + mccMnc);
String att_ringtone = null;
if((is_op07 && ("334090".equals(mccMnc))) || (is_op07 && !iccid && ("334050".equals(mccMnc)))){
att_ringtone = getNotificationUriByName(context, "ATT_Email_receive.mp3");
}
else{
att_ringtone = getNotificationUriByName(context, "Success.mp3");
}
Log.d(TAG, "ATT -> Calendar default notification uri = " + att_ringtone);
return att_ringtone;
}
如果需要获取电话铃声的uri可以把查询条件换成is_ringtone=1
在RingtonePlayer.java中是在用户还没有手动设置过google日历铃声时,有提示音时需要把默认铃声改为指定默认铃声
public void playAsync(Uri uri, UserHandle user, boolean looping, AudioAttributes aa) {
if (LOGD) Log.d(TAG, "playAsync(uri=" + uri + ", user=" + user + ")");
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Async playback only available from system UID.");
}
if (UserHandle.ALL.equals(user)) {
user = UserHandle.SYSTEM;
}
//Added for dt-4590368 by yonglin.liao 2017/05/04 begin {@
if(android.os.SystemProperties.get("ro.lct.tct_mx_att").equals("1")){
if (uri.toString().contains("android.resource://com.google.android.calendar/raw/")) {
String uriString = RingtoneManager.getNotificationUri(mContext);
uri = Uri.parse(uriString);
Log.d(TAG, "playAsync(Calendar ATT ringtone uri = " + uri + ")");
}
}
//Added for dt-4590368 by yonglin.liao 2017/05/04 end @}
mAsyncPlayer.play(getContextForUser(user), uri, looping, aa);
}
因为google日历的默认铃声是加载的自己内部apk里面的资源,uri比较好识别,但是gmail的默认铃声因为是直接调用的系统默认铃声,所以需要在NotificationManagerService.java中处理notification.sound即可
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
int[] idOut, int incomingUserId) {
if (DBG) {
Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
+ " notification" + notification);
}
if(android.os.SystemProperties.get("ro.lct.tct_mx_att").equals("1")){
if(notification.sound != null){
if(notification.sound.toString().contains("content://settings/system/notification_sound")){
if(pkg.contains("com.google.android.gm") || pkg.contains("com.tct.email")){
String uriString = RingtoneManager.getNotificationUri(getContext());
notification.sound = Uri.parse(uriString);
Log.d(TAG, "notification.sound(Calendar ATT ringtone uri = " + uriString + ")");
}
}
}
}
现在在用户还没有设置过默认铃声的情况下,来消息的铃声已经设置成指定的,但是当用户进去铃声列表时默认铃声还是系统的,所以需要在RingtonePickerActivity.java中设置列表的默认选中指定铃声mExistingUri
mExistingUri = intent
.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI);
Log.d("TAG","mExistingUri -->befor = " + mExistingUri);
// Added for defect 1278683,1251941 by yonglin.liao on 20160126 begin
if(android.os.SystemProperties.get("ro.lct.tct_mx_att").equals("1")){
if (mExistingUri != null) {
if((mExistingUri + "").contains("android.resource://com.google.android.calendar/raw/") ||
((mExistingUri + "").contains("content://settings/system/notification_sound") && groundAppPackageName().equals("com.google.android.gm"))) {
//Modified for dt-4590368 by yonglin.liao 2017/05/04 begin {@
String needChangeCalendarNotification = Settings.System.getString(this.getContentResolver(), "change_calendar_notification");
if ((needChangeCalendarNotification != null) && (needChangeCalendarNotification.equals("true"))) {
String uriString = Settings.System.getString(this.getContentResolver(), "calendar_att_notification_uri_string");
mExistingUri = Uri.parse(uriString);
Log.d(TAG, "set mExistingUri = " + mExistingUri);
} else {
mExistingUri = Settings.System.DEFAULT_NOTIFICATION_URI;
}
//Modified for dt-4590368 by yonglin.liao 2017/05/04 end @}
}
}
}
final AlertController.AlertParams p = mAlertParams;
p.mCursor = mCursor;
在这个方法中因为调用的是MediaProvider的Activity,传入的context没有实际意义,没法判断google日历的默认铃声,所以我们要想办法获取RingtonePickerActivity上一个Activity是否是google日历,构造方法如下
private String groundAppPackageName() {
ActivityManager am = (ActivityManager)getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
MtkLog.e(TAG, "tasks.get(0).baseActivity.getPackageName() = " + tasks.get(0).baseActivity.getPackageName());
return tasks.get(0).baseActivity.getPackageName();
}
现在设置默认铃声基本都已经设置完成,经过编译版本重新下载检查发现一个bug,进去apk的设置铃声页面,默认铃声还是显示系统默认铃声,但是点击进去列表是选中指定铃声
这是因为apk调用了RingtoneManager中Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType)方法,需要对ringtoneUri进行重新赋值成指定铃声
private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType) {
Log.d(TAG, "getRingtone() ringtoneUri ---> " + ringtoneUri
+ ", streamType = " + streamType);
if(android.os.SystemProperties.get("ro.lct.tct_mx_att").equals("1")){
boolean iccid = "1".equals(android.os.SystemProperties.get("persist.operator.subid", "0")) ? true : false; //Iccid ==1, return true;
boolean is_op07 = "OP07".equals(android.os.SystemProperties.get("persist.operator.optr", "")) ? true : false; //op07, return true;
String mccMnc = android.os.SystemProperties.get("persist.bootanim.mnc", ""); //this is enough for W2100, 334050 or 334090...
Log.d(TAG, "LCT dual-perso. iccid = " + iccid + ". is_op07 = " + is_op07 + ". mccMnc = " + mccMnc);
if(context.getPackageName().equals("com.google.android.gm") ||
context.getPackageName().equals("com.google.android.calendar") ||
context.getPackageName().equals("com.tct.email")) {
String uriString = getNotificationUri(context);
if((ringtoneUri + "").contains("content://settings/system/notification_sound")){
//Modified for dt-4590368 by yonglin.liao 2017/05/04 begin {@
ringtoneUri = Uri.parse(uriString);
Log.d(TAG, "att getRingtone = " + ringtoneUri);
//Modified for dt-4590368 by yonglin.liao 2017/05/04 end @}
}
if(is_op07 && iccid && ("334050".equals(mccMnc))){
//parameter 3; //OP07 + 334050 + iccid is 1;
if(isNotificationUri(context,ringtoneUri)) {
ringtoneUri = Uri.parse(uriString);
}
}
}
if(android.os.SystemProperties.get("ro.lct.tct_mx_att").equals("1")){
if(is_op07 && iccid && ("334050".equals(mccMnc))){
//parameter 3; //OP07 + 334050 + iccid is 1;
if(isNotificationUri(context,ringtoneUri)) {
ringtoneUri = getActualDefaultRingtoneUri(context,TYPE_NOTIFICATION);
}
}
}
}
try {
final Ringtone r = new Ringtone(context, true);
if (streamType >= 0) {
r.setStreamType(streamType);
}
r.setUri(ringtoneUri);
return r;
} catch (Exception ex) {
Log.e(TAG, "Failed to open ringtone " + ringtoneUri + ": " + ex);
}
return null;
}
到此为止,整个修改gmail和google日历默认铃声的事情全部完成。如果有其他第三方apk需要修改默认铃声的话,此方法同样生效。