需要获取simunlockstate状态,而这个不由我们这边控制,在免于提Mtk case的情况下,通过Telephony获取这个值,telephony是个服务apk,不能通过android.bp引入,考虑到这个原因,我觉得通过aidl以telephony为服务器端,MtkSettings为客户端,进行跨进程通信。下面说下步骤:
1.在服务器端新建aidl目录和文件,这里通过AndroidStudio去生成(New -> Aidl ->AIDL File)。生成完后记得rebuild一下,但是我这个是源码工程,rebuild后肯定会报错,但只要生成aidl生成了相应的派生类那就没关系。
// INetworkUnlockStatus.aidl
package com.android;
// Declare any non-default types here with import statements
interface INetworkUnlockStatus {
int getNetworkUnlockStatus();
}
2.服务器端建立service
public class NetworkUnlockService extends Service {
private final String TAG = "NetworkUnlockService";
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "getNetworkUnlockStatus has onBind");
return mUnlockManager;
}
private final INetworkUnlockStatus.Stub mUnlockManager = new INetworkUnlockStatus.Stub() {
@Override
public int getNetworkUnlockStatus() throws RemoteException {
Log.d(TAG, "getNetworkUnlockStatus has exec");
return getState();
}
};
int getState() {
MtkPhoneInterfaceManagerEx mtkPhoneInterfaceManagerEx = MtkPhoneInterfaceManagerEx.init((PhoneGlobals) getApplicationContext());
int simLockStateForRSU = mtkPhoneInterfaceManagerEx.getSimLockStateForRSU(0);
return simLockStateForRSU;
}
}
记得声明下并且export为true:
<service android:name=".NetworkUnlockService"
android:exported="true"
android:enabled="true">
<intent-filter
>
<action android:name="com.unlock.state.aidl"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
3.移植aidl包到客户端主目录,和main同级即可,确保包名一致
4.客户端合适的时机去启动远程service:
Intent intent = new Intent();
intent.setAction("com.unlock.state.aidl");
intent.setPackage("com.android.phone");
mContext.bindServiceAsUser(intent, mCon, Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
ServiceConnection:
private ServiceConnection mCon = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected");
INetworkUnlockStatus asInterface = INetworkUnlockStatus.Stub.asInterface(service);
if (null != asInterface) {
try {
networkUnlockStatus = asInterface.getNetworkUnlockStatus();
Log.d(TAG, "onServiceConnected networkUnlockStatus:" + networkUnlockStatus);
} catch (RemoteException e) {
Log.d(TAG, "onServiceConnected RemoteException e:" + e.getMessage());
e.printStackTrace();
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected");
}
};
注意,如果用的是bindService会爆错误无法运行Calling a method in the system process without a qualified user,根据源码就知道需要调用bindServiceAsUser,其实bindService后面也是调用了bindServiceAsUser的。
5.由于我这是在源码层的修改,所以需要在Android.bp进行aidl包的导入,注意在android R之前可能是Android.mk。下面代码只要看
srcs: [“src/**/*.java”,“aidl/com/android/INetworkUnlockStatus.aidl”],
这个位置即可:
// Build the Settings APK
android_library {
name: "MtkSettings-core",
platform_apis: true,
defaults: [
"MtkSettingsLibDefaults",
"SettingsLibDefaults",
"SettingsLib-search-defaults",
],
srcs: ["src/**/*.java","aidl/com/android/INetworkUnlockStatus.aidl"],
resource_dirs: [
"res",
"res_ext",
],
static_libs: [
"nfc_settings_adapter",
"androidx-constraintlayout_constraintlayout",
"androidx.slice_slice-builders",
"androidx.slice_slice-core",
"androidx.slice_slice-view",
"androidx.core_core",
"androidx.appcompat_appcompat",
"androidx.cardview_cardview",
"androidx.preference_preference",
"androidx.recyclerview_recyclerview",
"com.google.android.material_material",
"setupcompat",
"setupdesign",
"androidx-constraintlayout_constraintlayout-solver",
"androidx.lifecycle_lifecycle-runtime",
"androidx.lifecycle_lifecycle-extensions",
"guava",
"jsr305",
"com.mediatek.lbs.em2.utils",
"mtksettings-contextual-card-protos-lite",
"mtksettings-log-bridge-protos-lite",
"mtkcontextualcards",
"mtksettings-logtags",
"com.mediatek.settings.ext",
"statslog-mtksettings",
"zxing-core-1.7",
"android.hardware.dumpstate-V1.0-java",
"android.hardware.dumpstate-V1.1-java",
],
libs: [
"telephony-common",
"ims-common",
"app-compat-annotations",
"mediatek-telephony-base",
"mediatek-telephony-common",
"mediatek-common",
"mediatek-framework",
"mediatek-ims-common",
],
}
Telephony的Android.bp也是一样,我就不重复了。
客户端调用完整代码:
public class NetworkUnlockPreferenceController extends BasePreferenceController implements PreferenceManager.OnActivityStopListener {
private Context mContext;
String packageName = "com.assurance.rsuapp";
String className = "com.tmobile.rsuapp.MainActivity";
private String TAG = "NetworkUnlockPreferenceController";
private int networkUnlockStatus;
public NetworkUnlockPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mContext = context;
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
return false;
}
ComponentName componentName = new ComponentName(packageName, className);
startApp(componentName, null);
return true;
}
@Override
public CharSequence getSummary() {
startUnlockStatusService();
String state = "";
switch (networkUnlockStatus) {
case 0:
state = mContext.getResources().getString(R.string.locked_status);
break;
case 1:
state = mContext.getResources().getString(R.string.temporarily_locked_status);
break;
case 2:
state = mContext.getResources().getString(R.string.permanently_locked_status);
break;
}
return state;
}
@TargetApi(Build.VERSION_CODES.DONUT)
private void startUnlockStatusService() {
Intent intent = new Intent();
intent.setAction("com.unlock.state.aidl");
intent.setPackage("com.android.phone");
mContext.bindServiceAsUser(intent, mCon, Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
}
private ServiceConnection mCon = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected");
INetworkUnlockStatus asInterface = INetworkUnlockStatus.Stub.asInterface(service);
if (null != asInterface) {
try {
networkUnlockStatus = asInterface.getNetworkUnlockStatus();
Log.d(TAG, "onServiceConnected networkUnlockStatus:" + networkUnlockStatus);
} catch (RemoteException e) {
Log.d(TAG, "onServiceConnected RemoteException e:" + e.getMessage());
e.printStackTrace();
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected");
}
};
private void startApp(ComponentName com, String param) {
if (com != null) {
PackageInfo packageInfo;
try {
packageInfo = mContext.getPackageManager().getPackageInfo(com.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
packageInfo = null;
e.printStackTrace();
}
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(com);
if (param != null) {
Bundle bundle = new Bundle();
bundle.putString("flag", param);
intent.putExtras(bundle);
}
mContext.startActivity(intent);
} catch (Exception e) {
Log.e(TAG, "Exception", e);
}
}
}
@Override
public void onActivityStop() {
mContext.unbindService(mCon);
}
}
6.需要注意的是,我在preference里绑定的service,而preference类似activity,fragment的生命周期,所以我实现PreferenceManager.OnActivityStopListener,在对应的Activity销毁的时候进行解绑service。另外,Telephony编译生成的apk是不能直接adb install -r安装的,也不能直接push,需要先删除之前的telephony即可push,然后reboot就能生效,MtkSettings的话可以直接install -r,也不要重启。