0

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.

2 Answers2

2

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 method2, Accepted answer

For android 10,Accepted answer

I've mutated my code to fit my needs.

Dharman
  • 30,962
  • 25
  • 85
  • 135
-1

The way you want it, it is not possible. The only way to set your own app as the default for a given intent is with root access.

The only way to prompt the user to do this is to launch an intent which you app responds to and let the user choose your app to always open when the intent is launched.

Sergio Pardo
  • 774
  • 6
  • 17