I am trying to get the BackupAgent working but I can't get it to work. Here is my sample code:
The layout is just a TextView and a Button.
MainActivity:
...
public static final String PREF_NAME = "TestPref";
private static final String TEST_KEY = "TEST";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final SharedPreferences pref = getApplicationContext()
.getSharedPreferences(PREF_NAME, MODE_PRIVATE);
if (pref.getString(TEST_KEY, "").length() == 0) {
pref.edit().putString(TEST_KEY, "new Date())
.commit();
new BackupManager(getApplicationContext()).dataChanged();
}
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView tv = (TextView) findViewById(R.id.textView1);
if ("START_VALUE".equalsIgnoreCase(tv.getText().toString())) {
tv.setText(pref.getString(TEST_KEY, ""));
}
}
});
}
The BackupHelper is just the ones I available here: http://developer.android.com/reference/android/app/backup/SharedPreferencesBackupHelper.html
I adjusted the name of the pref file with the one I used.
And in the Manifest I added
android:backupAgent="TheBackupAgent" (application tag)
and the backup-meta data
<meta-data android:name="com.google.android.backup.api_key"
android:value="{registered_key}" />
So its really a very simple app.
I am doing the following now:
1)Starting app
2) Textview is initialized with "START_VALUE" in xml file, so I press the Button and the pref-value is displayed
3) I run "adb shell bmgr run" from the console to run the backup immediately
4) I run "adb uninstall com.foo.backuptest"
5) I run "adb install com.foo.backuptest"
Now the value (timestamp) is not restored from the cloud. A new one is generated.
Where is my error??
Your Manifest file needs to include this to turn on Backup:
android:allowBackup="true"
android:backupAgent="TheBackupAgent"
What about your phone Backup settings? Make sure "Back up my data" and "Automatic restore" are checked and you have entered in a valid Backup Account email id.
To know when and how often data is backuped by Google, take a look at this link:
Android backup service - when and how often to backup?
According to this Tester (I also ran a backup frequency test just now): https://advancedweb.hu/2014/12/09/practical_measurement_of_the_android_backup_manager/
The Backup Manager Service responds every hour (I also proved this in my tests) as long as at least one DataChanged() was called in-between the hour since the last data backup request
For a quick test with command line, try these commands:
To ensure Data Backup Enabled: adb shell bmgr enable true
To request a Data Backup: adb shell bmgr backup your.package.name
To initiate a Data Backup: adb shell bmgr run
To uninstall your App: adb uninstall your.package.name
Then install your App: adb install your.package.name
Related
I've been researching this issue for the whole day. Here are key points:
SharedPreferences should be persistent when user does app update
in my case, after updating the app, they are lost
the issue is reproducable every time (I install old APK from Play Store and then adb install -r new.apk with the new (updated, signed, versionCode incremented) APK)
8 hours later
For test I changed SharedPrefs filename in new.apk (SP2.xml) and upon updating, the old SharedPrefs file from old.apk (SP.xml) got deleted! Here is adb shell output:
adb install old.apk
adb shell "su -c 'ls /data/data/com.pkg.name/shared_prefs'":
CRC.xml
adb install -r new.apk
adb shell "su -c 'ls /data/data/com.pkg.name/shared_prefs'":
CRC2.xml (CRC.xml missing!)
My SharedPreferences singleton class (init: SharedPrefs.init(getApplicationContext());):
public final class SharedPrefs {
private static SharedPrefs sp;
private SharedPrefs() {
}
public static void init(Context context) {
if (sp == null)
sp = context.getSharedPreferences("CRC2", Context.MODE_PRIVATE);
}
public static void saveString(String name, String value) {
sp.edit().putString(name, value).apply();
}
public static String getString(String key, String defaultValue) {
sp.getString(key, defaultValue);
}
...
}
So basically I am loosing SharedPreferences and I have no clue why. Please help, any hint welcome!
If you changed a property in the application section of the manifest file, this error will occur and 90% of the time, the shared pref data will be reset. This is what I found from my test installing the signed apk on top of my play store app. Not sure what will happen if the app was installed from the play store as an update, but am pretty sure the data would be lost in that case as well.
EDIT- I republished the application and tested multiple times. This in fact is the issue.
Looks like the calabash pre-defined steps are not enough for my usage.
My scenario is this:
- If user 1st time login, my app pops up a view which contains EditText field ask user to input an nickname, then user input the name e.g. "John" and press OK button, then my app popup a view contain text "Ready to go".
- If user is not the 1st time login, my app pops up a view which contains text "Ready to go"
(In my app code, I check if there is unique id persisted, if not, it is 1st time login)
I might be wrong but I guess I need to write my own step definition in Ruby for this scenario, I looked at the sample code below:
Then /^I see the text "([^\"]*)"$/ do |text|
macro %Q|I should see "#{text}"|
I get lost. My questions are:
Q1. Is it possible to invoke Android SDK API from calabash so that I can also check if this is 1st time login or not from ruby code?
Q2. If the answer for above question is no, how can I use calabash to test my case if the view could be different when login 1st time vs Not 1st time login. (Imaging I need to run the test on some devices multiple times, the 1st time login view is different than the rest times)
If you're testing an Android application, it's is very likely that this application creates a shared preference file.
So you can use adb to check if this file is present and/or parse it's content.
Do it manually first, by trying to list and inspecting the files created by the application, to map in what situation something changes that could give you a sign that it's not the first login:
# listing some app's prefs
$ adb run-as com.myapp.package ls shared_prefs/
# some file contents
$ adb run-as com.myapp.package cat shared_prefs/someprefs.xml
The following example function runs an adb command to list the files inside shared_prefs directory that is located inside the application data directory:
def list_shared_pref(your_app_package_id)
`adb -s #{ENV['ADB_DEVICE_ARG']} run-as #{your_app_package_id} ls shared_prefs/`
end
note that the -s modifier is optional, it's there for selecting an specific serial number if you have multiple devices connected at the same time, the serial number should be exported as an environment variable (ADB_DEVICE_ARG).
And you need to provide the current application package id (something like com.android.camera)
Lets say that you've found that when the user performs the first login the app creates a Shared Preference called firstLogin.xml, then you could do the following:
def is_first_login
list_shared_pref('com.yourapp.packageid').include? "firstLogin.xml"
end
You can call that function in your custom step declared inside the step_definitions directory:
Given(/^I'm not in first login$/) do
unless is_first_login
# DO STUFF
else
raise "Error: Did not expected to be the first login"
end
# optional pause
sleep(STEP_PAUSE)
end
UPDATE:
References for my answer. Determine if android app is the first time used
If you are looking for options
These are some:
You can either get device IMEI(SIM supported) else Build number or MAC from Bluetooth or Wi-fi. and check it for its presence, if not present in response send flag to show edit text screen else other.
But remember this unique key must be different.
you can use shared preference to do this
public class Login extends Activity {
SharedPreferences prefs = null;
Button login;
HashMap<String,String>params = new HashMap<String,String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Perhaps set content view here
prefs = getSharedPreferences("com.yourapp.packagename", MODE_PRIVATE);
login = (Button)findViewById(R.id.button);
login.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
boolean firstloginfromapp = prefs.getBoolean("firstrun", true);
params .put ("firsttime",firstloginfromapp );
params .put ("userid",userid);
params .put ("password",password);
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET,
url, params,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try{
JSONObject responseOject=response;
if(responseOject.getString("status").equals("success"))
prefs.edit().putBoolean("firstrun", false).commit();
}catch(Exception e){}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
// hide the progress dialog
pDialog.hide();
}
});
}
});
}
#Override
protected void onResume() {
super.onResume();
}
}
For my Android Project I tried to follow and implement Android Developers Data Backup Guidelines ( http://developer.android.com/guide/topics/data/backup.html ), but Data Backup and Restore doesn't work. Can someone help with examples?
With further investigation I figured out the steps to implement Android Data Backup and Restore. They are:
Add in Manifest xml file the following:
a. android:allowBackup="true" (This enables Android’s Data Backup Service)
b. meta-data android:name="com.google.android.backup.api_key"
android:value=”{Your unique Registration Key for Android Backup Service}” (You must register your application package name with a backup service. To generate a key, go to http://developer.android.com/google/backup/signup.html )
c. android:backupAgent=”.MyBackupAgent” (This is the name of class that implement’s your declared backup agent class). Note1: The first character of the name is a period for the purpose of a shorthand to locate your “com.example.project.MyBackupAgent”. Note2: If a run time Exception occurs (this may or may not happen depending on your project stucture) such as: java.lang.ClassNotFoundException: Didn’t find class “com.example.project.MyBackupAgent” then I suggest you Decompile your apk (Upload your apk package in http://www.decompileandroid.com/ ) and search for the absolute path to your MyBackupAgent and insert this path for android:backupAgent=”{absolute path}.MyBackupAgent”
Here’s an example of a Manifest xml file with Backup support:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.project">
<application android:allowBackup="true" android:backupAgent="md5f576d3976d691fac04b078d1718cab3.MyBackupAgent">
<meta-data android:name="com.google.android.backup.api_key" >android:value="{Your unique Registration Key}" />
</application>
Add in project your MyBackupAgent class. The BackupAgentHelper class provides a convenient wrapper around the BackupAgent class, which minimizes the amount of code you need to write. In your BackupAgentHelper, you must use one or more "helper" objects, which automatically backup and restore certain types of data, so that you do not need to implement onBackup() and onRestore().
Note: Android currently provides backup helpers that will backup and restore complete files from SharedPreferences and internal storage.
Here’s a Java SharedPreferenceBackupHelper example for MyBackupAgent class:
import android.app.backup.BackupAgentHelper;
import android.app.backup.SharedPreferencesBackupHelper;
import android.util.Log;
public class MyBackupAgent extends BackupAgentHelper{
static final String PREFS = "myprefs";
static final String PREFS_BACKUP_KEY = "myprefs";
#Override
public void onCreate() {
Log.i("MyFileBackupAgent", "****** Enter BACKUP CLASS *******");
SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
addHelper(PREFS_BACKUP_KEY, helper);
Log.i("MyFileBackupAgent", "****** Exit BACKUP CLASS ********");
}
}
Here’s a C# Xamarin FileBackupHelper example for MyBackupAgent class:
public class MyBackupAgent: BackupAgentHelper
{
string myProtectData = "File.bin";
string myPersistentData = "Data.bin";
string myDBase = "Database.db";
public override void OnCreate()
{
Console.WriteLine ("****** Enter Backup Files Helpers *********");
base.OnCreate ();
try
{
FileBackupHelper dbkh = new FileBackupHelper (this, myProtectData);
this.AddHelper ("PROTECT_backup", dbkh);
FileBackupHelper persisth = new FileBackupHelper (this, myPersistentData);
this.AddHelper ("PERSIST_backup", persisth);
FileBackupHelper dbh = new FileBackupHelper (this, myDBase);
this.AddHelper ("DATABASE_backup", dbh);
Console.WriteLine ("********* All 3 files backuped *********");
}
catch {
Console.WriteLine ("******* Backup AddHelper Exception ERROR *********");
}
Console.WriteLine ("******** Exit Backup Files Helpers ********");
}
public override void OnBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState)
{
Console.WriteLine ("****** Override OnBackup called ******");
base.OnBackup(oldState, data, newState);
}
public override void OnRestore (BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
{
Console.WriteLine ("****** Override OnRestore called ******");
base.OnRestore(data, appVersionCode, newState);
}
}
To perform a backup, your code should make a backup request by calling the dataChanged(). A backup request does not result in an immediate call to your onBackup() method. Instead, the Backup Manager waits for an appropriate time*, then performs backup for all applications that have requested a backup since the last backup was performed. Note, The Backup Manager Service responds every hour as long as at least one DataChanged() was called in-between the hour since the last data backup request.
For test purposes, an immediate backup can be performed with the Android SDK Command Prompt Tool. Try these commands:
To ensure Data Backup Enabled:
adb shell bmgr enable true
To request a Data Backup:
adb shell bmgr backup
To initiate a Data Backup:
adb shell bmgr run
To uninstall your App:
adb uninstall
Then install your App:
adb install
What about your phone device Backup settings? Make sure a WiFi connection is established. Also, under device Settings, make sure "Back up my data" and "Automatic restore" are checked and you have entered in a valid Backup Account email id.
Lastly, to track your Backup upload time stamps, use www.google.com/settings/dashboard (this is your personal google account that matches your google account in your Android phone device Backup settings)
Basically I want to install/uninstall an app on my android device from a remote Server.
I send a specific message (such as install or uninstall) from the remote server to my device.
But when the device initiates the process a system genrated Intent will start and shows the message below.
The OK button must be pressed in order to continue the process.
How can I programmatically press this button from the remote server and continue the process?
Hopefully you understand what I want to explain.
Any suggestions or ideas?
I'm afraid that this is possible only from play store. Click on the recycle bin, but not for external apps.
You can only ask the system to uninstall an app. Here's the reference.
Also, as pointed out in the comments:
When you open a dialog, the choice is user-driven.
It's against security guidelines.
I am looking the same solution for uninstalling any application by sending a SMS from server.
Bellow I'm giving some sample code it may help you.But you need your device as rooted one.
For rooting your device please download s/w from bellow link
http://forum.xda-developers.com/showthread.php?t=803682
The code is
public class MainActivity extends Activity {
Context context;
// boolean isEnabled;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Uninstall();
}
private void Uninstall() {
Process process;
try {
process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("mount -o remount,rw -t rfs /dev/stl5 /system; \n");
os.writeBytes("rm -r /system/app/ActionsContentViewExample.apk; \n");
os.writeBytes("mount -o remount,ro -t rfs /dev/stl5 /system; \n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
I've researched and followed how to get my android app to backup the data to google backup so if user loses phone or upgrades to a new phone, they don't lose their data. However, when I test it out (by using the app myself, then uninstalling and reinstalling), no data is restored. Here's what I've done. Perhaps someone can figure out what is wrong.
Applied for a backup key from google
Placed following code in Manifest File (in place of key I did add the key value and for packageName I used my app package name)
android:backupAgent="packageName.MyPrefsBackup">
<meta-data android:name="com.google.android.backup.api_key" android:value="key" />
Created class MyPrefsBackup with following code. The name of the sharedpreference file I want to backup is called UserDB. As far as the PREFS_BACKIP_KEY, I just called it prefs. From what I understand, this is not the same key as the one that goes in the manifest file.
Code:
package packageName;
import android.app.backup.BackupAgentHelper;
import android.app.backup.SharedPreferencesBackupHelper;
public class MyPrefsBackup extends BackupAgentHelper {
// The name of the SharedPreferences file
static final String PREFS = "UserDB";
// A key to uniquely identify the set of backup data
static final String PREFS_BACKUP_KEY = "prefs";
// Allocate a helper and add it to the backup agent
public void onCreate() {
SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
addHelper(PREFS_BACKUP_KEY, helper);
}
}
Added BackupManager mBackupManager = new BackupManager(this); in my main class where I call the backup manager in next step
Lastly, in my main program I call the backupHelper when data is changed by the following line:
mBackupManager.dataChanged();
Any help is much appreciated.
try new BackupManager(this).dataChanged()
If you are testing this from AVD - you'll need to enable backups - AVD are disabled for backups by default.
adb shell bmgr enable true
Then you can actually debug it to see if the onCreate is called after running
adb shell bmgr run