I have created a Messaging App and can be made default from settings. My goal is to prompt a sms app default chooser within my app.
I actually found a way to achieve my goal. For android 10, it's made possible by the RoleManager class:
RoleManager roleManager;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
roleManager = getApplicationContext().getSystemService(RoleManager.class);
if (roleManager.isRoleAvailable(RoleManager.ROLE_SMS)) {
if (roleManager.isRoleHeld(RoleManager.ROLE_SMS)) {
Toast.makeText(getApplicationContext(), "PrismApp set as default.", Toast.LENGTH_SHORT).show();
Intent i = new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS);
startActivity(i);
} else {
Intent roleRequestIntent = roleManager.createRequestRoleIntent(RoleManager.ROLE_SMS);
startActivityForResult(roleRequestIntent, 2);
}
}
}
Expected result: android 10
For android versions prior to android 10, found two methods a simple one and a complex one but worth it. For the simple method:
String myPackageName = getPackageName();
Intent setSmsAppIntent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
setSmsAppIntent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, myPackageName);
startActivity(setSmsAppIntent);
Expected result: simple method
The second method's:
private static final int DEF_SMS_REQ = 0;
private AppInfo selectedApp;
private void selectDefaultSmsPackage() {
@SuppressLint("QueryPermissionsNeeded") final List<ResolveInfo> receivers = getPackageManager().queryBroadcastReceivers(new
Intent(Telephony.Sms.Intents.SMS_DELIVER_ACTION), 0);
final ArrayList<AppInfo> apps = new ArrayList<>();
for (ResolveInfo info : receivers) {
final String packageName = info.activityInfo.packageName;
final String appName = getPackageManager().getApplicationLabel(info.activityInfo.applicationInfo).toString();
final Drawable icon = getPackageManager().getApplicationIcon(info.activityInfo.applicationInfo);
apps.add(new AppInfo(packageName, appName, icon));
}
apps.sort(new Comparator<AppInfo>() {
@Override
public int compare(AppInfo app1, AppInfo app2) {
return app1.appName.compareTo(app2.appName);
}
});
new AppsDialog(this, apps).show();
}
public void onAppSelected(AppInfo selectedApp) {
this.selectedApp = selectedApp;
Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, selectedApp.packageName);
startActivityForResult(intent, DEF_SMS_REQ);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == DEF_SMS_REQ) {
String currentDefault = Telephony.Sms.getDefaultSmsPackage(this);
boolean isDefault = selectedApp.packageName.equals(currentDefault);
String msg = selectedApp.appName + (isDefault ?
" successfully set as default" :
" not set as default");
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}
public static class AppInfo {
String appName;
String packageName;
Drawable icon;
public AppInfo(String packageName, String appName, Drawable icon) {
this.packageName = packageName;
this.appName = appName;
this.icon = icon;
}
@NonNull
@Override
public String toString() {
return appName;
}
}
Also your Activity must implement OnAppSelectedListener interface.
public class MainActivity extends AppCompatActivity implements AppsDialog.OnAppSelectedListener { ... }
Next, create a class AppsDialog that extends Dialog:
public class AppsDialog extends Dialog implements AdapterView.OnItemClickListener {
public interface OnAppSelectedListener {
void onAppSelected(MainActivity.AppInfo selectedApp);
}
private final Context context;
private final List<MainActivity.AppInfo> apps;
public AppsDialog(Context context, List<MainActivity.AppInfo> apps) {
super(context);
if (!(context instanceof OnAppSelectedListener)) {
throw new IllegalArgumentException(
"Activity must implement OnAppSelectedListener interface");
}
this.context = context;
this.apps = apps;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("Select default SMS app");
final ListView listView = new ListView(context);
listView.setAdapter(new AppsAdapter(context, apps));
listView.setOnItemClickListener(this);
setContentView(listView);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
((OnAppSelectedListener) context).onAppSelected(apps.get(position));
dismiss();
}
private static class AppsAdapter extends ArrayAdapter<MainActivity.AppInfo> {
public AppsAdapter(Context context, List<MainActivity.AppInfo> list) {
super(context, R.layout.list_item, R.id.text, list);
}
public View getView(int position, View convertView, ViewGroup parent) {
final MainActivity.AppInfo item = getItem(position);
View v = super.getView(position, convertView, parent);
((ImageView) v.findViewById(R.id.icon)).setImageDrawable(item.icon);
return v;
}
}
}
And a linear layout(list_item) for the AppsDialog class:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingTop="1dp"
android:paddingBottom="1dp"
android:paddingStart="8dp"
android:paddingEnd="8dp">
<ImageView android:id="@+id/icon"
android:layout_width="36dp"
android:layout_height="36dp"
android:contentDescription="Icon Here" />
<TextView android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:ellipsize="marquee" />
That's pretty much it. All this was made possible by:
For android 10,Accepted answer
I've mutated my code to fit my needs.