Requesting root access for android app - android

I know there are already questions about that here, but I tried all the answers given without success.
There's a simple CheckBoxPreference (titled "Root"):
<CheckBoxPreference
android:key="root"
android:title="#string/root"
android:summary="#string/root_summary"
android:defaultValue="false" />
Now I need to set the OnPreferenceChangeListener on it and gain root access. If so the checkbox should be checked, otherwise it should not:
public class Settings extends PreferenceActivity implements OnPreferenceChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
findPreference("root").setOnPreferenceChangeListener(this);
}
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String key = preference.getKey();
if ("root".equals(key) && !((CheckBoxPreference) preference).isChecked()) {
try {
Process p = Runtime.getRuntime().exec("su");
p.waitFor();
Log.d("Settings", Integer.toString(p.exitValue()));
if (p.exitValue() == 255) {
Log.d("Settings", "###NO ROOT###");
return false;
}
} catch (Exception e) {
Log.d("Settings", "###NO ROOT###");
Log.d("Settings", e.getMessage());
return false;
}
Log.d("Settings", "!!!ROOT!!!");
}
return true;
}
}
Superuser prompts correctly for root access. Denying however also returns true, as exitValue is 1 (???) and allowing freezes the whole app (I guess at p.waitFor).
I'm currently running Superuser 3.1.3 with su binary 3.1.1 (newest versions).
Taking a look into logcat I can see the following message: Activity pause timeout for ActivityRecord{42c0ebb8 com.example/.gui.Settings}

The command you're running is just su which will, I suspect, run a shell as superuser. You're waiting (indefinitely) for that shell to finish.
You need to specify su some-command-here-which-needs-to-run-as-root.
Unfortunately, there is no way to achieve superuser permissions for the Java code within your Android project. The root-ness applies only to commands which are spawned by su itself.

Related

adb shell settings put secure sysui_nav_bar commands on Android Oreo 8.0 not works without root

I'm trying to use this "set of commands" on Android Oreo but i have some issue. For testing i'm using this command on my Nexus 5x:
adb shell settings put secure sysui_nav_bar "space,recent;home;back,space"
So i decided to implement this command inside my app and try without root help. In the app manifest i added the permission to write secure settings:
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
Then in my MainActivity i added a button to run the command that you read before.
testButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
Process process = Runtime.getRuntime().exec("settings put secure sysui_nav_bar \"space,recent;home;back,space\"");
} catch (Exception e) {Toast.makeText(getApplicationContext(), "" + e, Toast.LENGTH_LONG).show();}
}
});
Once my app was built i ran it on my 5x and via adb i typed this command to allow to write secure settings:adb shell pm grant com.customizer.smart.batterysavercustomizer android.permission.WRITE_SECURE_SETTINGS and this command was excuted without errors. But when i try to tap on my "testButton" nothing happened and 0 erorrs inside androidmonitor.
Last try that i did was with root help. I edited my preview command button:
testButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
Process process = Runtime.getRuntime().exec("su -c settings put secure sysui_nav_bar \"space,recent;home;back,space\"");
} catch (Exception e) {Toast.makeText(getApplicationContext(), "" + e, Toast.LENGTH_LONG).show();}
}
});
When i tapped on my testButton the app asked to garant root permission, and it works. But how is possible that on the same phone the app "Custom navigation bar" app that uses the same adb command works without root ?.
I followed this: guide on XDA
You should use Settings class instead of Runtime.getRuntime().exec()
testButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_SECURE_SETTINGS) == PackageManager.PERMISSION_GRANTED) {
Settings.Secure.putString(context.getContentResolver(), "sysui_nav_bar", valueToSave);
} else {
//Write secure Settings permission not granted
//Show instructions about how to grant it via ADB
}
}
});

Android BackupAgent never called

I am trying to implement a custom backupAgentHelper to backup my app's database file. I've gone through the docs several times but whenever I try to force backup, the backupAgentHelper on Create/onBackup/onRestore are never called.
Manifest has the following under application:
android:allowBackup="true"
android:backupAgent="myBackupHelper"
android:restoreAnyVersion="true"
and metadata
<meta-data
android:name="com.google.android.backup.api_key"
android:value="<my-api-key>" />
myBackupHelper:
public class myBackupHelper extends BackupAgentHelper{
public static String DATABASE_NAME = "db.dat";
#Override
public void onCreate(){
log.d("Backup oncreate called");
FileBackupHelper hosts = new FileBackupHelper(this, this.getExternalFilesDir(DATABASE_NAME).getAbsolutePath());
addHelper(DATABASE_NAME,hosts);
}
#Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) {
log.d("backup onbackup called");
try {
//class is the lock since we are using static synchronized methods to read/write
synchronized (DBManager.class) {
super.onBackup(oldState, data, newState);
log.d("Backedup");
}
} catch (IOException e) {
log.d("Backup error, Unable to write to file: " + e);
}
}
#Override
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState){
log.d("Backup onrestore called");
try {
//class is the lock since we are using static synchronized methods to read/write
synchronized (DBManager.class) {
super.onRestore(data, appVersionCode, newState);
}
} catch (IOException e) {
log.d("Backup error, Unable to read from file: " + e);
}
}
I initialize the BackupManager in the mainactivity as follows:
BackupManager bm = new BackupManager(getApplicationContext());
and call bm.dataChanged(); when the database changes.
In testing, I use adb to force backup:
./adb shell bmgr backup com.test.android.backuptest
./adb shell bmgr run
but the logs are never hit and when i reinstall, data is never restored.
Note: backup and restore settings are enabled and the device has over the required api 8 so I have no idea why its not being hit!
The reason why my backupAgentHelper functions were never called is because of the transport being used.
Doing
./adb shell bmgr list transports
showed
android/com.android.internal.backup.LocalTransport
*com.google.android.gms/.backup.BackupTransportService
For some reason the goodle transportservice wasn't working but changing it to the internal localtransport with
./adb shell bmgr transport android/com.android.internal.backup.LocalTransport
fixed my problem and now logs are showing up.

Install / Unistall from shell command in Android

I want to implement a silent installer-from-apk-file and unistaller-package in Android.
The topic has largely been discussed on SO and elsewhere but I can't apply any for some reason that I'm missing.
The scope is obviously hard to achieve because, if successful, it would be a serious security breach in Android. BUT, I need to implement it for a special project, not for the consumer market.
There are two approaches:
to generate a custom ROM from a source code (AOSP or Cyanogen mod, for example), by tweaking the PackageManager installer (in fact just to remove the user acceptance dialog boxes).
to do it programmatically by creating a process as super user and executing an 'adb shell pm install'. I previously installed 'su' in /system/xbin and I test during run time that RootTools.rootIsAvailable().
For the first case, I digged into the Froyo source code but got into a dead end with a #hide marked method.
For the second I've first tried the commands from the terminal
adb shell pm install /mnt/sdcard/HelloAndroid.apk
and
adb shell pm uninstall com.example.helloandroid
Both work OK. Then, I used the following code, the development being tested on a rooted emulator (2.2 - Froyo):
#Override
public void onClick(View v) {
switch (v.getId())
{
case R.id.btnInstall:
try {
install = Runtime.getRuntime().exec("su\n");
DataOutputStream os = new DataOutputStream(install.getOutputStream());
os.writeBytes("pm install /mnt/sdcard/HelloAndroid.apk\n");
os.writeBytes("exit\n");
os.flush();
install.waitFor();
if (install.exitValue() == 0) {
Toast.makeText(MainActivity.this, "Success!", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(MainActivity.this, "Failure. Exit code: "+String.valueOf(install.exitValue()), Toast.LENGTH_LONG).show();
}
}
catch (InterruptedException e) {
logError(e);
}
catch (IOException e) {
logError(e);
}
break;
case R.id.btnUninstall:
try {
install = Runtime.getRuntime().exec("su\n");
install=Runtime.getRuntime().exec("pm uninstall "+txtPackageName.getText().toString()+"\n");
} catch (Exception e) {
logError(e);
}
break;
}
}
To avoid typos and other trims I hardcoded the apk file parameter of the command for the installation; on 'case R.id.btnInstall' the command is not executed and the exit is on "Failure" with exit value 1, meaning that "the class cannot be found"; no clue what that means ...
I appreciate your help!
EDITED: I have the clean solution, I shall post the answer from A-Z as soon as I have the time and the code in the right form!!
As I promised here is the solution to this problem, without doing any forcing to the system other than having to install the whole application in the /system/app directory. I have followed, then did some fixing to the excellent article here: http://paulononaka.wordpress.com/2011/07/02/how-to-install-a-application-in-background-on-android/. I have downloaded the zip file referenced in the article then, (I tried to keep the same class names where possible):
created a new project and a main activity as entry point
package com.example.silentinstuninst;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import com.example.instuninsthelper.ApplicationManager;
import com.example.instuninsthelper.OnDeletedPackage;
import com.example.instuninsthelper.OnInstalledPackage;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener {
Process install;
Button btnInstall, btnUninstall;
EditText txtApkFileName, txtPackageName;
public static final String TAG = "SilentInstall/Uninstall";
private static ApplicationManager am;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeValues();
}
private void initializeValues() {
btnInstall = (Button) findViewById(R.id.btnInstall);
btnUninstall = (Button) findViewById(R.id.btnUninstall);
txtApkFileName = (EditText) findViewById(R.id.txtApkFilePath);
txtPackageName = (EditText) findViewById(R.id.txtPackageName);
btnInstall.setOnClickListener(this);
btnUninstall.setOnClickListener(this);
try {
am = new ApplicationManager(this);
am.setOnInstalledPackage(new OnInstalledPackage() {
public void packageInstalled(String packageName, int returnCode) {
if (returnCode == ApplicationManager.INSTALL_SUCCEEDED) {
Log.d(TAG, "Install succeeded");
} else {
Log.d(TAG, "Install failed: " + returnCode);
}
}
});
am.setOnDeletedPackage(new OnDeletedPackage() {
public void packageDeleted(boolean succeeded) {
Log.d(TAG, "Uninstall succeeded");
}
});
} catch (Exception e) {
logError(e);
}
}
private void logError(Exception e) {
e.printStackTrace();
Toast.makeText(this, R.string.error+e.getMessage(), Toast.LENGTH_LONG).show();
}
#Override
public void onClick(View v) {
switch (v.getId())
{
case R.id.btnInstall:
// InstallUninstall.Install(txtApkFileName.getText().toString());
try {
am.installPackage(Environment.getExternalStorageDirectory() +
File.separator + txtApkFileName.getText().toString());
} catch (IllegalArgumentException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalAccessException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (InvocationTargetException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} // install package
break;
case R.id.btnUninstall:
// InstallUninstall.Uninstall(txtPackageName.getText().toString());
try {
am.uninstallPackage(txtPackageName.getText().toString());
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logError(e);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logError(e);
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logError(e);
}
break;
}
}
}
create in /src the package com.example.instuninsthelper. I have added there the ApplicationManager.java and OnInstalledPackage.java files
inserted the following code inside the ApplicationManager class:
private OnDeletedPackage onDeletedPackage;
class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
public void packageDeleted(boolean succeeded) throws RemoteException {
if (onDeletedPackage != null) {
onDeletedPackage.packageDeleted(succeeded);
}
}
}
created, under the same com.example.instuninsthelper package the file OnDeletedPackage.java with the following code:
package com.example.instuninsthelper;
public interface OnDeletedPackage {
public void packageDeleted(boolean succeeded);
}
in the android.content.pm package (the namespace SHOULD not be changed) I modified the IPackageDeleteObserver.java, with this result:
package android.content.pm;
public interface IPackageDeleteObserver extends android.os.IInterface {
public abstract static class Stub extends android.os.Binder implements android.content.pm.IPackageDeleteObserver {
public Stub() {
throw new RuntimeException("Stub!");
}
public static android.content.pm.IPackageDeleteObserver asInterface(android.os.IBinder obj) {
throw new RuntimeException("Stub!");
}
public android.os.IBinder asBinder() {
throw new RuntimeException("Stub!");
}
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
throw new RuntimeException("Stub!");
}
}
public abstract void packageDeleted(boolean succeeded)
throws android.os.RemoteException;
}
build the application in Eclipse and deploy it to the emulator
in the emulator: home button > Settings > applications > ...uninstall the application (because it is not installed in /system/app, and we just needed the generation of the apk file)
do the following to root the emulator (so that we can write in /system/app; other solution, that I have used, is to generate a custom ROM with this app included into the /system/app):
download the su file from here http://forum.xda-developers.com/showthread.php?t=682828http://forum.xda-developers.com/showthread.php?t=682828. Rename it to su.zip
then from the console:
* adb shell mount -o rw,remount -t yaffs2 /dev/block/mtdblock03 /system
* adb push su.zip /system/xbin/su
* adb shell chmod 06755 /system
* adb shell chmod 06755 /system/xbin/su
from the console, go to the /bin directory of the project, then enter:
* adb push .apk /system/app
finally, always from the console, enter:
* adb shell am start -n com.example.silentinstuninst/com.example.silentinstuninst.MainActivity
enjoy!
Don't know, but just a idea:
I think that you are writing in the standarout, not executing a command nor giving extra data to the process via its input. I think it should be:
Runtime.getRuntime().exec("pm install /mnt/sdcard/HelloAndroid.apk\n");
Hope this helps.
Installing in the /system/app directory is essentially the same as requiring root.
Assuming you have root, check out RootTools. Then you can do:
if (RootTools.isAccessGiven()) {
CommandCapture command = new CommandCapture(0, "pm install " + PATH_TO_APK);
RootTools.getShell(true).add(command).waitForFinish();
}
Note that waitForFinish() is a blocking call!
Well you can do this also with the PackageManager directly (requires root access):
Create an app with a platform-sdk which has the interfaces publicly (create or download it, and configure eclipse)
In the app directly call the hidden API functions which allow silent install/remove.
Install the APK on your device as a system app by copying it to /system/app (root needed)
See this: http://forum.xda-developers.com/showthread.php?t=1711653
Runtime.getRuntime().exec("pm install /mnt/sdcard/HelloAndroid.apk\n");
This works for me, although two more additional details have to be done:
Add android:sharedUserId="android.uid.system" in AndroidManifest.xml.
Signed the apk with the system key.
But in this way it seems there is no way to tell whether the installation is succeeded, so I will try #Ginger's method later.
For all who are still having problem: you will need a rooted device and use
Process result = Runtime.getRuntime().exec("pm install -r -d MyApp.apk /system/app")
If you are getting result code 9 (error code 9) you will need to delete your apk from the device and push it back (PUSH not INSTAL!).
Go to the device shell and Push the apk
launcher=MyApp.apk
$adb shell su -c "mount -o remount,rw -t rfs /dev/stl5 /system"
$adb push $launcher /sdcard/$launcher
$adb shell su -c "chmod 644 /system/app/$launcher"
Now you are able to use pm install without getting an error. Hope it will help somebody.

Is there a way to hide the system bar in Android 3.0? It's an internal device and I'm managing navigation

In Android 2.3 and below, you could make an application full screen, and then "hijack" the menu/back/search buttons by just returning false onKeyDown()... and registering the app as a default home launcher application, that way, there's no way to exit the application.
In Android 3.0 (Honeycomb) the navigation buttons (System Bar) is always present, I'd like to hide it. Is it possible?
FYI, I am not publishing this application on the Android Market. This is an internal application for devices that are going to be used internally, I need to secure the device.
Since this is not possible to do using a public API, I have found a way to do it in a very "hack-ish" way that requires a rooted device.
Update: as user864555 pointed below, this is another solution
$ adb remount
$ adb shell mv /system/app/SystemUI.odex /system/app/SystemUI.odexold
$ adb shell mv /system/app/SystemUI.apk /system/app/SystemUI.apkold
$ adb reboot
"That code disable the app SystemUI which is the actually menu bar. Which that modification, you will also gain the space of that system bar. But make sure to have a back button or something to exit."
That works great as well. Please vote for his answer. I will try to keep this one updated as much as I can.
Update: Here's a third method. A way to do it programmatically or using the command line. Found here: http://android.serverbox.ch/?p=306
This method requires root access, but you don't need to change the LCD Density, keeping the same as the original, and you can get the UI nav bar back really quick and easy without having to reboot everytime.
The blog post also shows how to implement it on your Android application, remember it requires root, and it might not be a great idea to do so unless your application is running on a kiosk or your own device, please do not implement this method on an app that's published in the Android market or anywhere public.
To stop/remove/disable the system bar (need to be su before issuing this command):
$ service call activity 79 s16 com.android.systemui
To restore the system bar just simply issue this command:
$ am startservice -n com.android.systemui/.SystemUIService
It's that easy. Hopefully ICS gets released soon along with the source code so that anyone can build Android for our Kiosk tablets.
You cannot hide the system bar on Android 3.0.
If you have access to system file, you can do this (mine is unlocked and rooted, so i'm not sure what you need, I haven't tried with a factory fresh xoom):
adb shell
cd /system/app/
mv SystemUI.odex SystemUI.odexold
mv SystemUI.apk SystemUI.apkold
exit
adb reboot
That code disable the app SystemUI which is the actually menu bar. With that modification, you will also gain the space of that system bar, but make sure that you have a back button or something to exit in your app.
Edit:
If you have problems with read-only file, you mint need to mount the /system directory as read-write. To do so, use this command in adb shell (Source: http://forum.xda-developers.com/showthread.php?t=1159495&page=5)
mount -o remount,rw /dev/block/stl6 /system
You can remount it as read-only using that command:
mount -o remount,ro /dev/block/stl6 /system
Edit:
This methods allow the soft keyboard to be displayed normally when needed.
Here is related code with my previous answer. It automatically hide the status bar and show it back again when finish. Important: to show it back again, the code have to restart system_server which take some time to boot again and during that time, you will see the honeycomb booting animation. That's the only I find for now to show the statusbar again. Restarting SystemUI is not enought. And because of that, it will shutdown your app when restart system_server.
This code need a rooted os with superuser installed on.
package com.projects;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TableLayout.LayoutParams;
// http://www.stealthcopter.com/blog/2010/01/android-requesting-root-access-in-your-app/
public class FullScreenTestActivity extends Activity implements Button.OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try
{
Process p;
p = Runtime.getRuntime().exec("su");
// Attempt to write a file to a root-only
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("mount -o remount,rw /dev/block/stl6 /system\n");
os.writeBytes("mv /system/app/SystemUI.odex /system/app/SystemUI_Old.odex\n");
os.writeBytes("mv /system/app/SystemUI.apk /system/app/SystemUI_Old.apk\n");
os.writeBytes("mount -o remount,ro /dev/block/stl6 /system\n");
// Close the terminal
os.writeBytes("exit\n");
os.flush();
p.waitFor();
new AlertDialog.Builder(this)
.setIconAttribute(android.R.attr.alertDialogIcon)
.setMessage("Android Honeycomb StatusBar removed successfully!")
.show();
// Set action for exiting.
Button cmdExit = new Button(this);
cmdExit.setText("Exit");
cmdExit.setOnClickListener(this);
this.addContentView(cmdExit, new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
}
catch (Exception e)
{
ShowErrorGlobal(e);
}
}
public void onClick(View v) {
try
{
Process p;
p = Runtime.getRuntime().exec("su");
// Attempt to write a file to a root-only
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("mount -o remount,rw /dev/block/stl6 /system\n");
os.writeBytes("mv /system/app/SystemUI_Old.odex /system/app/SystemUI.odex\n");
os.writeBytes("mv /system/app/SystemUI_Old.apk /system/app/SystemUI.apk\n");
os.writeBytes("mount -o remount,ro /dev/block/stl6 /system\n");
String systemServerPID = GetSystemServerPID();
if (systemServerPID != null)
os.writeBytes("kill " + systemServerPID + "\n");
// else ... manual reboot is required if systemServerPID fail.
// Close the terminal
os.writeBytes("exit\n");
os.flush();
p.waitFor();
}
catch (Exception e)
{
ShowErrorGlobal(e);
}
}
public String GetSystemServerPID()
{
try
{
Process p = Runtime.getRuntime().exec("ps -n system_server");
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
reader.readLine(); // Skip header.
return reader.readLine().substring(10, 16).trim();
}
catch (Exception e)
{
return null;
}
}
protected void ShowErrorGlobal(Exception e)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream stream = new PrintStream( baos );
e.printStackTrace(stream);
stream.flush();
new AlertDialog.Builder(this)
.setIconAttribute(android.R.attr.alertDialogIcon)
.setTitle("Epic fail")
.setMessage("Error: " + new String( baos.toByteArray() ))
.show();
}
}
Although this doesn't answer the question of 'locking' the screen, you can hide the status bar without being root by using the setSystemUiVisibillity api(API level 11).
Some pseudocode:
public MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstance) {
//...
final View mainView = findViewById(R.id.you_main_view_id);
mainView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
//Register a listener for when the status bar is shown/hidden:
final Context context = getApplicationContext();
mainView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener () {
#Override
public void onSystemUiVisibilityChange(int visibility) {
if ((visibility == View.SYSTEM_UI_FLAG_VISIBLE)) {
//Do stuff here...pause the video/game?
} else {
//Do other stuff here..resume the video/game?
}
}
});
}
}
This will hide the status bar until the user clicks along the lower edge of the screen, in which case the status bar will get shown (it'll get hidden again after a few seconds).
Make sure you've specified targetSdkVersion="11" or higher in your manifest.
The application HideBar can be used to hide the system bar on android tablets (HC, ICS, JB). It contains an optional kiosk mode that can be used to lock down tablets completely and also other options like a hidden back button. It is GPL software. Contact the developer (me, see email on applications website) if this application has to be installed in large volumes.
For others who have had this problem:
If you haven't set the android:targetSdkVersion properly in your AndroidManaifest.xml file, setSystemUiVisibility has no effect (unlike other advanced APIs which work whether or not the targetSDKVersion has been set properly or not).
I had accidentally left my targetSdkVersion at 8. Bumping it up to 16 immediately caused setSystemUIVisiblity to have the desired effect.
Yes it is possible to do if you have root access on the device.
This code can hide and show the StatusBar by killing it`s proccess and calling it back again.
package com.example.statusbar;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
public class MainActivity extends Activity {
String commandToExecute;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
commandToExecute = "/system/xbin/su";
executeShellCommand(commandToExecute);
Button btHideStatusBar = (Button) findViewById(R.id.buttonHide);
Button btShowStatusBar = (Button) findViewById(R.id.buttonShow);
btHideStatusBar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
commandToExecute = "/system/xbin/su -c /system/bin/service call activity 42 s16 com.android.systemui";
executeShellCommand(commandToExecute);
}
});
btShowStatusBar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
commandToExecute = "/system/xbin/su -c /system/bin/am startservice -n com.android.systemui/.SystemUIService";
executeShellCommand(commandToExecute);
}
});
}
private boolean executeShellCommand(String command) {
try {
Runtime.getRuntime().exec(command);
return true;
} catch (Exception e) {
return false;
}
}
}
As of 4.4 you can do this (this question is very old, but always comes up on this topic):
setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE)
https://developer.android.com/training/system-ui/immersive.html
if you want to hide navigation bar through out the application then here is the most simplest way.
just write this code in your application tag in manifest file
> <Application
> android:theme="#android:style/Theme.Black.NoTitleBar.Fullscreen" <!--
> other parameters of application tag-->
> >
android:theme="#android:style/Theme.Black.NoTitleBar.Fullscreen
or
mainView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE)
No, the task bar is still there, with three gray dots instead classic icons

How to programmatically clear application data

I am developing automated tests for an android application (using Robotium). In order to ensure the consistency and reliability of tests, I would like to start each test with clean state (of the application under test). In order to do so, I need to clear the app data. This can be done manually in Settings/Applications/Manage Applications/[My App]/Clear data
What is the recommended way to get this done programmatically?
You can use the package-manager tool to clear data for installed apps (similar to pressing the 'clear data' button in the app settings on your device).
So using adb you could do:
adb shell pm clear my.wonderful.app.package
Following up to #edovino's answer, the way of clearing all of an application's preferences programmatically would be
private void clearPreferences() {
try {
// clearing app data
Runtime runtime = Runtime.getRuntime();
runtime.exec("pm clear YOUR_APP_PACKAGE_GOES HERE");
} catch (Exception e) {
e.printStackTrace();
}
}
Warning: the application will force close.
you can clear SharedPreferences app-data with this
Editor editor =
context.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE).edit();
editor.clear();
editor.commit();
and for clearing app db, this answer is correct -> Clearing Application database
From API version 19 it is possible to call ActivityManager.clearApplicationUserData().
((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).clearApplicationUserData();
Check this code to:
#Override
protected void onDestroy() {
// closing Entire Application
android.os.Process.killProcess(android.os.Process.myPid());
Editor editor = getSharedPreferences("clear_cache", Context.MODE_PRIVATE).edit();
editor.clear();
editor.commit();
trimCache(this);
super.onDestroy();
}
public static void trimCache(Context context) {
try {
File dir = context.getCacheDir();
if (dir != null && dir.isDirectory()) {
deleteDir(dir);
}
} catch (Exception e) {
// TODO: handle exception
}
}
public static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// <uses-permission
// android:name="android.permission.CLEAR_APP_CACHE"></uses-permission>
// The directory is now empty so delete it
return dir.delete();
}
If you have just a couple of shared preferences to clear, then this solution is much nicer.
#Override
protected void setUp() throws Exception {
super.setUp();
Instrumentation instrumentation = getInstrumentation();
SharedPreferences preferences = instrumentation.getTargetContext().getSharedPreferences(...), Context.MODE_PRIVATE);
preferences.edit().clear().commit();
solo = new Solo(instrumentation, getActivity());
}
Using Context,We can clear app specific files like preference,database file.
I have used below code for UI testing using Espresso.
#Rule
public ActivityTestRule<HomeActivity> mActivityRule = new ActivityTestRule<>(
HomeActivity.class);
public static void clearAppInfo() {
Activity mActivity = testRule.getActivity();
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(mActivity);
prefs.edit().clear().commit();
mActivity.deleteDatabase("app_db_name.db");
}
if android version is above kitkat you may use this as well
public void onClick(View view) {
Context context = getApplicationContext(); // add this line
if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) {
((ActivityManager) context.getSystemService(ACTIVITY_SERVICE))
.clearApplicationUserData();
return;
}
What is the recommended way to get this done programmatically?
The only possible option is to run ADB command adb shell pm clear package before the test. The biggest problem is that it's kind of headache combining tests execution and shell commands.
However, we (at Mediafe) came with some solution that can work for you on regular unrooted device. All you need to do is to add an annotation. All the rest is done by running simple bash script.
Just add #ClearData annotation before ANY of your tests and tada 🎉, ADB clear command will be executed before the test execution.
This is an example of such test:
#Test
#ClearData
public void someTest() {
// your test
}
The idea is as follows
Read all tests by using adb shell am instrument -e log true
Build execution plan by parsing the output from (1)
Run the execution plan line by line
Using the same idea these are all options you can easily support:
Clear data
Clear notification bar
Parameterize
Filter and run by tags
Use only annotations. Like this:
#Test
#ClearData
#Tags(tags = {"sanity", "medium"})
#Parameterized.Repeat(count = 3)
public void myTest() throws Exception {
String param = params[index];
// ...
}
Bonus! 🎁 For each failed test:
Collect Logcat + stacktrace
Record video (mp4)
Dump DB (sqlite)
Dump default shared preferences (xml)
Collect dumpsys files like: battery, netstats and other.
In general, it's easy to add more options, since the tests are executed one by one from bash script rather than from gradle task.
📗 The full blog post: https://medium.com/medisafe-tech-blog/running-android-ui-tests-53e85e5c8da8
📘 The source code with examples: https://github.com/medisafe/run-android-tests
Hope this answers 6 years question ;)
This way added by Sebastiano was OK, but it's necessary, when you run tests from i.e. IntelliJ IDE to add:
try {
// clearing app data
Runtime runtime = Runtime.getRuntime();
runtime.exec("adb shell pm clear YOUR_APP_PACKAGE_GOES HERE");
}
instead of only "pm package..."
and more important: add it before driver.setCapability(App_package, package_name).

Categories

Resources