Whenever a user installs my app for the first time an instalationID is generated randomly (say Instalationid =123). I am trying to back up this instalationID, so that when the user uninstalls and then installs my app the old instalationID (123) will be assigned to him again, rather than a new one. After all, he is the same user.
I have a shared preferences file, called SESSION_INFO_PREFERENCE_KEY, that holds the instalationID and I try to back up the shared preferences file. The back up manager is:
public class ADCBackupAgent extends BackupAgentHelper {
// The name of the SharedPreferences file instalation ID
static final String INSTID = "SESSION_INFO_PREFERENCE_KEY"; //SESSION_INFO_INSTALLATION_UID
// A key to uniquely identify the set of backup data
static final String INSTID_BACKUP_KEY = "inst_id";
// Allocate a helper and add it to the backup agent
#Override
public void onCreate() {
Log.i("OnCreate Method","!!!!!!ON create called!!!!!!!!!!");
SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, INSTID);
addHelper(INSTID_BACKUP_KEY, helper);
}
}
Also, whenever the instalationID is generated for the first time I perform a call to the Back up manager such as:
//this pointing to the current Activity
BackupManager backUpManager = new BackupManager(this);
backUpManager.dataChanged();
For the sake of completenes:
<application
android:icon="#drawable/application_icon"
android:label="#string/app_name"
android:name="MyAppName"
android:theme="#style/FragmentTheme"
android:allowBackup="true"
android:backupAgent=".ADCBackupAgent">
...
<meta-data android:name="com.google.android.backup.api_key" android:value="AEdPqr..." />
</application>
My code works perfectly fine when I do the back up on the local transport (using the bmgr tool), however, when I try to back up the data on Google's cloud strage I get:
04-28 15:12:24.305: W/BackupTransportService(390): Not ready for backup request right now: [OperationScheduler: enabledState=true lastSuccess=2014-04-03/15:10:49 moratoriumSet=2014-04-28/14:43:18 moratorium=2014-04-29/14:43:18 trigger=1969-12-31/19:00:00]
Furthermore, the onCreate() Method is never called.
This does not happen when I back up the data on the local transport, i.e., onCreate() is called and "Not ready for backup request right now" does not appear.
Related
I am sharing data between two my app, this is my code for get the data from the shared pref in app A
try {
final Context mContext = createPackageContext("com.example.demo", Context.MODE_PRIVATE);
final String val = mContext.getSharedPreferences("pref_name",Context.MODE_PRIVATE).getString(MY_KEY,"");
Log.e("sharedtest",val);
finish();
} catch (Exception e) {
e.printStackTrace();
}
this code is inside the onCreate() method, I don't have any more code anywhere. My problem is that, if I save the some value in my app B and than start my app A the saved data were correctly retrieved at first time, after retrieving the data my activity were finishing (I have only one activity), and if I start my launcher icon and start my app A, there is no updated data(it is the same), which where changed from app B.
also if I kill my app from system app settings and launch it like first time launch updated data is here, every data change needs my app killing from settings, how can I fix that? what I'm missing?
I found solution it may be a trick but it works fine for me,
after my app A finishes its job, I'm calling the system exit method.
System.exit(1);
it makes app "A" to be exit and finish job completely
After that I had the latest updated data in my preferences
I'm creating an app for Android. Part of the desired app functionality is that the user can select a special printer (let's just call it Transfer Printer) which will pass on the document-to-be-printed to a process running on an external server.
What steps do I need to take to add a custom printer to the list of printers in the Android print panel, accessible from the Print option of the Overflow menu?
It is desirable to use the existing Android print panel functionality rather than, for example, an additional Share option in the App Selector because of user experience considerations; it won't be intuitive to the user to click Share rather than Print for the desired functionality.
Prior research
There is an existing similar question which has gathered little interest since it was posted some time ago. The asker has identified the PrintManager class as a lead but I believe that the PrintService class is likely to be more fruitful:
A print service is responsible for discovering printers, adding discovered printers, removing added printers, and updating added printers.
The same page details Declaration and Configuration of the print service. I've done so as below.
Attempted Execution
Declaration and Configuration
In AndroidManifest.xml:
...
<application
... >
...
<service
android:name=".TransferPrintService"
android:permission="android.permission.BIND_PRINT_SERVICE"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.printservice.PrintService" />
</intent-filter>
<meta-data
android:name="android.printservice"
android:resource="#xml/transfer_print_service" />
</service>
</application>
Meta-data
It's unclear to me exactly where the meta-data is supposed to be specified. From SERVICE_META_DATA section of the PrintService page:
This meta-data must reference a XML resource containing a print-service tag.
In res/xml/transfer_print_service.xml:
<print-service
android:label="TransferPrintService"
android:vendor="Company Ltd." />
TransferPrintService Class
This creates a custom PrinterDiscoverySession. My goal at this stage is to just get a printer appearing in the print panel and work from there.
public class TransferPrintService extends PrintService {
public TransferPrintService() {
}
#Override
public void onPrintJobQueued(PrintJob printJob) {
printJob.start();
printJob.complete();
}
#Override
public PrinterDiscoverySession onCreatePrinterDiscoverySession() {
return new TransferPrinterDiscoverySession(this);
}
#Override
public void onRequestCancelPrintJob(PrintJob printJob) {
}
}
The service is started in a BroadcastReceiver on an ACTION_BOOT_COMPLETED intent.
TransferPrinterDiscoverySession Class
This actually creates the custom printer.
public class TransferPrinterDiscoverySession extends PrinterDiscoverySession {
private transferPrintService printService;
private static final String PRINTER = "Transfer Printer";
public transferPrinterDiscoverySession(TransferPrintService printService) {
this.printService = printService;
}
#Override
public void onStartPrinterDiscovery(List<PrinterId> printerList) {
PrinterId id = printService.generatePrinterId(PRINTER);
PrinterInfo.Builder builder =
new PrinterInfo.Builder(id, PRINTER, PrinterInfo.STATUS_IDLE);
PrinterInfo info = builder.build();
List<PrinterInfo> infos = new ArrayList<>();
infos.add(info);
addPrinters(infos);
}
#Override
public void onStopPrinterDiscovery() {
}
#Override
public void onValidatePrinters(List<PrinterId> printerIds) {
}
#Override
public void onStartPrinterStateTracking(PrinterId printerId) {
PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId,
PRINTER, PrinterInfo.STATUS_IDLE);
PrinterCapabilitiesInfo.Builder capBuilder =
new PrinterCapabilitiesInfo.Builder(printerId);
capBuilder.addMediaSize(PrintAttributes.MediaSize.ISO_A4, true);
capBuilder.addResolution(new PrintAttributes.Resolution(
"Default", "Default", 360, 360), true);
capBuilder.setColorModes(PrintAttributes.COLOR_MODE_COLOR
+ PrintAttributes.COLOR_MODE_MONOCHROME,
PrintAttributes.COLOR_MODE_COLOR);
capBuilder.setMinMargins(PrintAttributes.Margins.NO_MARGINS);
PrinterCapabilitiesInfo caps = capBuilder.build();
builder.setCapabilities(caps);
PrinterInfo info = builder.build();
List<PrinterInfo> infos = new ArrayList<PrinterInfo>();
infos.add(info);
addPrinters(infos);
}
#Override
public void onStopPrinterStateTracking(PrinterId printerId) {
}
#Override
public void onDestroy() {
}
}
Major Concerns
This doesn't produce an additional printer option.
Is the arrangement of documents correct? Specifically, having the <print-service> tag in a separate XML document under res? Trying to place the tag anywhere in the AndroidManfiest.xml document produces IDE errors.
How do I call into the TransferPrintService? As an example, suppose I'm in Chrome, I open the Overflow menu, and select Print... Which PrintService is invoked? How do I make sure it's mine?
Am I on completely the wrong track here?
The trick I was missing was actually enabling the Print Service via the Android Settings menu. Actually doing this wasn't as straightforward as I would have hoped as the device manufacturer had removed the setting from the menu. It should be right under Accessibility in the System section of the menu.
I ended up installing the Cloud Print app by Google, which gave me access to the Print Service settings temporarily (to enable the Cloud Print service). Once in here I noticed that my own service was, in fact, present.
For posterity: To avoid un-installing and re-installing Cloud Print every time you want to change the Print Service settings, use the following SQLite3 commands, either with adb shell or from Terminal Emulator (or similar):
sqlite3 data/data/com.android.providers.settings/databases/settings.db
You should now have access to the Settings database and be using the SQLite3 command line shell. The settings of interest are located in the secure table and are enabled_print_services and enabled_on_first_boot_system_print_services. You can check if these settings already exist by using:
.dump secure
If they don't, then use the following commands:
INSERT INTO secure VALUES(<id>, 'enabled_on_first_boot_system_print_services', 'com.companyname.appservice/com.companyname.appservice.TransferPrintService');
INSERT INTO secure VALUES(<id>, 'enabled_print_services', 'com.companyname.appservice/com.companyname.appservice.TransferPrintService');
You should, of course, replace 'com.companyname.appservice' with your own package and 'TransferPrintService' with your own print service. If these setting names do already exist, and your print service isn't listed, then you'll need to UPDATE instead of INSERT INTO:
UPDATE secure SET value = '<existing print services>:<new print service>' WHERE name = 'enabled_on_first_boot_system_print_services';
UPDATE secure SET value = '<existing print services>:<new print service>' WHERE name = 'enabled_print_services';
You'll need to make sure to include any existing print services as part of the UPDATE command; listed print services are separated by a colon ":".
Reboot the device to apply the updates to the settings database.
I have a class, that executes some command in background. Class method is executed asynchronously (by using AsyncTask) and when command finishes, it posts event with command result. Then, new activity is started. To do this, I added inside OnCreate method to MainActitity:
ssh = new SshSupport();
ssh.Connect();
ssh.ExecuteCommand(commandType);
//..................................
ssh.eventHandler = new ISshEvents()
{
#Override
public void SshCommandExecuted(SshCommandsEnum commandType, String result)
{
if (progressDialogExecuting.isShowing()) progressDialogExecuting.dismiss();
Intent intent = new Intent(MainActivity.this, ResultListActivity.class);
intent.putExtra("result", result);
intent.putExtra("commandType", commandType);
startActivity(intent);
}
So it works as should. My commands starts in background and when finished, my event fires and displays new activity with results (all results are received via getIntent().getExtras() and then formatted to be displayed as should).
Problem: on result activity I have "Refresh" button. When pressed, all data should be refreshed. So I need to execute ssh.ExecuteCommand(commandType); again to get refreshed data. Note that I don't want to open new ssh connection for this. Instead, I want to use already opened connection and simply execute my command again.
So I made my 'ssh' static and I used MainActivity.ssh.ExecuteCommand(commandType); on refresh button press. It works, but obviously, it causes to create second instance of ResultListActivity, instead of refreshing data on existing one.
I can even avoid to creating result activity again by checking if it's already exists (for example by adding 'active' boolean static variable to it). However, it won't help me because I still have no any possibility to refresh data inside my existing activity.
So, how can I do it?
No responses, so I'm answering to my own question. My solution was:
- Change my activity launchMode to singleTop
- Override method onNewIntent
In this case each time I start this activity: if activity already exists it won't be created again. Instead, onNewIntent method will be called.
http://developer.android.com/guide/topics/manifest/activity-element.html#lmode
http://developer.android.com/reference/android/app/Activity.html#onNewIntent%28android.content.Intent%29
However, I'm not sure if approach like this is good. How do you think?
I am wanting to create a plugin I can share and reuse easily, but as such I won't know the package or activity name for the main application. So far, I can get all of this information from code. My problem is that I have receivers which need to call a method on the main application activity if it's running. Here's where I am so far:
My application creates an alarm, and I am saving the name of the app activity in the shared preferences (this works):
PackageManager manager = context.getPackageManager();
String packageClassName = manager.getLaunchIntentForPackage(context.getPackageName()).getComponent().getClassName();
// store the packageClassName in shared prefs
Then, in my alarm receiver, I am able to retrieve the class name successfully. I then iterate over all running tasks to see if an activity with the same name is running. This is working without issue.
If the activity is found in the list of running tasks, I need to call a method on the activity instance. This is where I am stuck - I keep getting an object is not an instance of class error on the invoke. I am using reflection (try/catch blocks removed for brevity):
// get packageClassName from shared prefs
// loop over running tasks (ActivityManager -> getRunningTasks)
// if a tasks "topActivity" matches my packageClassName, then proceed...
Class<?> appClass = Class.forName( packageClassName );
Method isActiveMethod = appClass.getMethod( "isAppActive" );
// The following doesn't work b/c "activity" is not an instance of my app
Boolean isActive = (Boolean)isActiveMethod.invoke( activity );
I am loading a PreferenceScreen from an xml file to use as the screen to configure a new event so I'm attempting to clear and reset the values of the SharedPreference this activity is using. The problem I'm encountering is that when attempting to move to using a named preference manager, it seems the preference gets cleared but when I select an EditTextPreference element, the old data is still the default entered text on the popup.
In my onCreate method I'm attempting to initialize the preferences, clear them, then set to default values. My understanding from the dev resources were that there's no way to clear/reset in one step..
private static final String PREFNAME = "newmeetingactivity.preferences";
//load preferences and set name
addPreferencesFromResource(R.layout.newmeeting_preferences);
getPreferenceManager().setSharedPreferencesName(PREFNAME);
getPreferenceManager().setSharedPreferencesMode(MODE_PRIVATE);
//Clear the preferences
_sharedPreferences = getPreferenceManager().getSharedPreferences();
SharedPreferences.Editor ed = _sharedPreferences.edit();
ed.clear();
ed.commit();
//Load default preferences from file again
PreferenceManager.setDefaultValues(this, _sharedPreferences.toString() , MODE_PRIVATE, R.layout.newmeeting_preferences, true);
Edit: To try to better explain what I'm attempting to do (in case my approach is way off): I need to clear shared preferences used on a given activity while not interfering with the settings from other activities (as they should persist indefinitely).
Could you instead try using the PreferenceManager.getDefaultSharedPreferences(context) to get your prefs.
Edit:
adb shell into your application after you choose to reset the values. If you look at the preference file you will see that it's default value has been set. Try refreshing your activity. One way I did this was by simply killing it from the Applications menu. When the activity restarts it will have the expected default value.