Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically open 'About device' page in Settings correctly?

startActivity(new Intent(android.provider.Settings.ACTION_DEVICE_INFO_SETTINGS)); opens this page in Samsung devices:

enter image description here

However, I want it to open this page like the rest of Android devices, how can I do it?

enter image description here

like image 453
Panjeet Avatar asked Jun 12 '20 12:06

Panjeet


People also ask

How do I get to programmatically in Android settings?

To achieve this just use an Intent using the constant ACTION_SETTINGS, specifically defined to show the System Settings: startActivity(new Intent(Settings. ACTION_SETTINGS));

How do I open location settings in android programmatically?

Get current location settingsTask<LocationSettingsResponse> task = client. checkLocationSettings(builder. build()); When the Task completes, your app can check the location settings by looking at the status code from the LocationSettingsResponse object.

How do I access settings in Android Studio?

Click File > Settings (on macOS, Android Studio > Preferences) to open the Settings dialog.


2 Answers

As Pedro Antonio said:

If it doesn't work for SAMSUNG devices I'm afraid it will probably not be possible. At least with no official answer. Many times vendors modify stock Android so for SAMSUNG devices settings app is different than stock AOSP, and the official method will not work.

When we call:

Intent i = new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS);
startActivity(i);

we are referring to activity com.android.settings.Settings$DeviceInfoSettingsActivity and in logs we can see that activity is started

2020-06-26 11:33:43.804 4838-5126/? I/ActivityManager: START u0 {act=null typ=null flg=0x8000 cmp=ComponentInfo{com.android.settings/com.android.settings.Settings$DeviceInfoSettingsActivity}} from uid 1000

On devices like Huawei P10, Software Information data is part of DeviceInfoSettingsActivity. After some digging i found out that on Samsung S7 device Software Information is Fragment that is called inside DeviceInfoSettingsActivity

2020-06-26 11:44:25.780 7103-9703/? D/Settings: packageName : com.android.settings className : com.android.settings.SubSettings
2020-06-26 11:44:25.812 7103-7103/? D/SubSettings: Launching fragment com.samsung.android.settings.deviceinfo.SoftwareInfoSettings

I am not sure is it possible to access DeviceInfoSettingsActivity code (I couldn't) and see if you can send some extra data to open specific Fragment. So at this point i do not believe that it is possible to launch that specific fragment from intent.

like image 140
Apollo Avatar answered Sep 20 '22 12:09

Apollo


The main point is it seems impossible. Let's look at what is the reason.

The DeviceInfoSettingsActivity can be opened by an intent call like:

Intent intent = new Intent(android.provider.Settings.ACTION_DEVICE_INFO_SETTINGS);
startActivity(intent);

or

Intent intent = new Intent();
intent.setClassName(
    "com.android.settings",
    "com.android.settings.Settings$DeviceInfoSettingsActivity"
);
startActivity(intent)

As you can see here:

https://android.googlesource.com/platform/packages/apps/Settings/+/master/src/com/android/settings/Settings.java

Settings and all of its inner classes are children of SettingsActivity. By taking a look at source code of SettingsActivity, we found out it is possible to show a sub-settings, passing the fragment name as an intent extra with key ":settings:show_fragment" to the SettingsActivity:

SettingsActivity#onCreate() then SettingsActivity#launchSettingFragment()

If we dig into logs where the target screen is shown, we'd see that the target fragment name is com.samsung.android.settings.deviceinfo.SoftwareInfoSettings.

But the problem is that there is a check on fragment names at SettingsActivity#isValidFragment() which allows specific fragments to navigate to and they are SettingsGateway#ENTRY_FRAGMENTS:

protected boolean isValidFragment(String fragmentName) {
    // Almost all fragments are wrapped in this,
    // except for a few that have their own activities.
    for (int i = 0; i < SettingsGateway.ENTRY_FRAGMENTS.length; i++) {
        if (SettingsGateway.ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
    }
    return false;
}

The alternative for showing other fragments in settings is to open SubSettings activity which overrides the isValidFragment to accepts every fragment.

@Override
protected boolean isValidFragment(String fragmentName) {
    Log.d("SubSettings", "Launching fragment " + fragmentName);
    return true;
}

That is exactly what happens when the SoftwareInfoSettings is shown:

D/Settings: packageName : com.android.settings className : com.android.settings.SubSettings
D/SubSettings: Launching fragment com.samsung.android.settings.deviceinfo.SoftwareInfoSettings

Unfortunately, starting the SubSettings from uid except launcher's uid isn't possible, because it is not an exported activity to be visible from the outside:

AndroidManifest.xml:

<activity android:name=".SubSettings"
    android:parentActivityName="Settings"
    android:theme="@style/Theme.SubSettings"/>

If you try to run:

Intent intent = new Intent();
intent.setClassName(
    "com.android.settings",
    "com.android.settings.SubSettings"
);
intent.putExtra(
    ":settings:show_fragment",
    "com.samsung.android.settings.deviceinfo.SoftwareInfoSettings"
);
startActivity(intent);

will see this error log:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.aminography.settingsapp, PID: 14566
java.lang.SecurityException: Permission Denial: 
    starting Intent { flg=0x10000000 cmp=com.android.settings/.SubSettings (has extras) } 
    from ProcessRecord{fac1d09 14566:com.aminography.settingsapp/u0a104} (pid=14566, uid=10104) 
    not exported from uid 1000

Unfortunately, since isValidFragment() and SettingsGateway#ENTRY_FRAGMENTS are parts of the platform, not your application's runtime, it's impossible to change them even with reflection.

like image 28
aminography Avatar answered Sep 20 '22 12:09

aminography