Home » Android » Is it possible to restart Android App after calling ActivityManager.clearApplicationUserData()

Is it possible to restart Android App after calling ActivityManager.clearApplicationUserData()

Posted by: admin June 15, 2020 Leave a comment

Questions:

My current Android Application needs to call

 ActivityManager.clearApplicationUserData()

to simulate the user clearing App storage

Which works fine.

A side effect of calling clearApplicationUserData() is that the App is (understandably) closed.

Which gives a poor user experience.

I am having difficulty in restarting my Application once I have called clearApplicationUserData().

I have tried using startActivity, Alarm Manager with Pending Intent, Foreground/Background service.

Nothing works.

Is it impossible to restart an Android App having called clearApplicationUserData()?

How to&Answers:

(1th answer: this answer only works on limited situation.it’s not a complete answer)

public boolean clearApplicationUserData ()

Description

Return: true if the application successfully requested that the application’s data be erased; false otherwise.

As reference website stated , we have a returnee before application is being closed. so, we are going to use this returnee in order to restart app.

if(ActivityManager.clearApplicationUserData)
{
     doRestart = true;
}

when Activity onDestroy() and onStop() are called restart app.

   @Override
   protected void onDestroy() {
       super.onDestroy();
       if(doRestart){
           Intent intent = new Intent(this, Activity.class);
           this.startActivity(intent);
       }
   }

    @Override
    protected void onStop() {
        super.onStop();
        if(doRestart){
            Intent intent = new Intent(this, Activity.class);
            this.startActivity(intent);
        }
    }

We put restart action in both onDestroy() and onStop() in order to make sure app will be restarted again.

And also , i think it’s good idea to force stop activity before OS stops it.

if(ActivityManager.clearApplicationUserData)
{
     doRestart = true;
     finish(); <= i mean this 
}

it’s because , it makes sure that onDestroy() and onStop() will be invoked.

Answer:

My suggestion might sound trivial but, have you consider not calling ActivityManager.clearApplicationUserData()?

Here what the docs says about this method:

Permits an application to erase its own data from disk. This is
equivalent to the user choosing to clear the app’s data from within
the device settings UI. It erases all dynamic data associated with the
app — its private data and data in its private area on external
storage — but does not remove the installed application itself, nor
any OBB files.

So in order to mimic this behavior you just need to clear you internal and external storage directories. No permissions are needed to access any of those.

Answer:

(2th answer: i need much more contribution on it)

After 8 hours researching in Android OS and Android Developers Website in order to find a solution to restart activity when clearApplicationUserData is invoked. Finally, i would be able to find a nice/hacking solution.

This solution looks like zidane dribble 🙂

Let’s intro the solution. at first, clearApplicationUserData clears all the clues of application when is invoked like tasks, notifications, alarms and etc. therefore, explicit Activity calling is impossible.

implicit way is the only possible way of calling activity.

After a couple of tests i found that application manifest registered intent-filters wouldn’t be removed and they are able to listen for incoming system broadcasts.

Approximately , 98% of system broadcasts wouldn’t be received by cleared application and that 2% remained might not be broadcasted very soon.

so what to do ? hmmm ? come on man i must found a solution …

bingo , i must trigger something in order to system broadcast it <= looks hacking 🙂

so i decide to choose WIFI_STATE_CHANGED because

  • Easy Access permission
  • System Broadcasts it on delay <= this makes sure that app is closed
    before broadcast

manifest.xml

<receiver
   android:name=".PackageDataClearedReceiver"
   android:enabled="true"
   android:exported="true">
     <intent-filter android:priority="100">
       <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
       <action android:name="android.net.wifi.STATE_CHANGE" />
     </intent-filter>
 </receiver>

MainActivity.java

public class MainActivity extends AppCompatActivity {
    ActivityManager am;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        AppCompatButton btn = findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        am = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
                        if (am != null) {
                            ExecutorService pool = Executors.newFixedThreadPool(2);
                            final Collection<Future> futures = new HashSet<Future>();
                            futures.add(pool.submit(new Runnable() {
                                @Override
                                public void run() {
                                    WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
                                    wifiManager.setWifiEnabled(true);
                                    wifiManager.setWifiEnabled(false);
                                    am.clearApplicationUserData();
                                }
                            }));
                            for (Future future : futures) {
                                future.isDone();
                            }
                        }

                    }
                }).start();
            }
        });
    }
}

demo

enter image description here

keep in mind, it’s just A minimum viable product that need to be developed more in order to make it work perfect.

Answer:

Hopefully this will still serve as help

Question: Is it impossible to restart an Android App having called clearApplicationUserData()?
Ans: No

Once you call clearApplicationUserData() then call the below method.

private void triggerRebirth(Context context) {
     PackageManager packageManager = context.getPackageManager();
     Intent intent = packageManager.getLaunchIntentForPackage(context.getPackageName());
     ComponentName componentName = intent.getComponent();

     Intent mainIntent = Intent.makeRestartActivityTask(componentName);
     context.startActivity(mainIntent);
     Runtime.getRuntime().exit(0);
}

Happy Coding.

Answer:

Clearing the app data on the device through the API clearApplicationUserData() resets the app as if it were just installed. As you have found, any alarms and broadcasts registered with your app are also cleared. The most efficient way to keep your app in the foreground would be to clear the data yourself, as others have pointed out, rather than using the API. Here is an example: https://stackoverflow.com/a/9073473/949224


However, if you are determined to use the API (which does guarantee all data is cleared) and the app is force-stopped, I have a suggestion:

Create a small companion app that can be launched just prior to you clearing your app data. The companion app simply re-launches your app, possibly after a short time-out.

    Intent launchIntent = getPackageManager().getLaunchIntentForPackage("example.com.testrelaunchapp");
    if (launchIntent != null) {
        startActivity(launchIntent);//null pointer check in case package name was not found
    } else {
        Log.w( TAG, "Unable to resolve launch activity of relauncher companion app");
    }

    ((ActivityManager)getSystemService(Context.ACTIVITY_SERVICE))
                    .clearApplicationUserData();   

The companion app itself needs to close afterwards, and ideally should be hidden from the Activity Stack etc..

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final Intent launchIntent = getPackageManager().getLaunchIntentForPackage("example.com.yourmainapp");
    if (launchIntent != null) {
        Handler handler = new Handler(getMainLooper());
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.i( TAG, "About to act on launchIntent");
                launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
                startActivity(launchIntent);
                finish();
                System.exit(0);
            }
        }, 1000);
    }    
 }     

I have seen this work with Android 6.0, but no guarantees it would be versatile and work across the board. There would be more to do to make the companion app UI-less if desired and to be hidden from the phone’s launcher. You would also probably want to bundle the APK as a file within your own app and install it upon first run, which would need the user to enable installation from “Unknown sources” (non-Play store). It can be done through intents to the right System settings, if needed, but users would need a good explanation why this is needed.

So, as I was saying, the simpler approach is to clear the data and app permissions yourself.