Android: Autostart app and load preferences - android

I have a problem with initializing my app properly after the autostart.
I've managed to get an autostart to work, after a reboot the app is shown as started but the timer's are not.
My guess is that the "onCreate" function of MyApp is not called when I call the context.startService(). The timers are set in the doActivity() function of MyApp.
I would greatly appreciate any tips on what I could be doing wrong or links to good tutorials. :)
The manifest:
<activity android:name=".MyApp"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="MyApp_Receiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>[/syntax]
MyApp_Receiver is a BoradcastReciever with the following two functions
public void onReceive(Context context, Intent intent) {
// Do Autostart if intent is "BOOT_COMPLETED"
if ((intent.getAction() != null) && (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")))
{
// Start the service
context.startService(new Intent(context, MyApp.class));
}
// Else do activity
else
MAIN_ACTIVITY.doActivity();
}
public static void setMainActivity(MyApp activity)
{
MAIN_ACTIVITY = activity;
}
MyApp extends PreferenceActivity and has an onCreate() and a doActivity(), the doActivity() reads out the preferences and sets a timer depending on them.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Show preferences
addPreferencesFromResource(R.xml.preferences);;
// Register Preference Click Listeners
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
// Prepare for one-shot alarms
if (mIntent == null)
{
mIntent = new Intent(MyApp.this, MyApp_Receiver.class);
mSender = PendingIntent.getBroadcast(MyApp.this,
0, mIntent, 0);
MyApp_Receiver.setMainActivity(this);
}
// Refresh and set all timers on start
doActivity();
}

The timers are set in the doActivity()
function of MyApp.
That will never work. MyApp is an activity, one that will not be created until the user goes in and launches it.
Read your SharedPreferences in onReceive() and set the alarms there.

Related

How to make a screen not fall asleep if the app runs on boot?

I have the app which must start on device' boot. It works well but the problem is that when the app finishes booting, the screen is already dark. How can I make it not fall asleep?
My Receiver:
<receiver
android:enabled="true"
android:exported="true"
android:name=".view.receivers.BootReceiver"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
public class BootReceiver extends BroadcastReceiver {
private final static String LOG_TAG = BootReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Log.i(LOG_TAG, "Loading after booting...");
Intent startCalendarActivityIntent = new Intent(context, CalendarActivity.class);
startCalendarActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startCalendarActivityIntent);
} else {
Log.e(LOG_TAG, "Error while restarting after boot.");
}
}
}
On this device is Android 6.0 .
You can either use wakelocks, which need certain permissions, or you can put a flag in your onCreate method, which according to the docs does not require a permission.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
The wakelock documentation gave the example above.

Android getIntent() not returning expected Intent when launched from history

I have a problem with Activity lifecycle and NFC:
I have a MainActivity with the AndroidManifest.xml entry:
<activity
android:name=".ui.main.MainActivity"
android:finishOnTaskLaunch="true"
android:launchMode="singleTask"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/androidbeam" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/nfctag" />
</intent-filter>
<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="#xml/nfc_tech_filter" />
</activity>
where launchMode="singleTask" is used for NFC to prevent multiple MainActivity instances.
In MainActivity I have the following code:
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Timber.d("onCreate");
setContentView(R.layout.activity_main);
handleIntent(getIntent());
}
#Override
protected void onNewIntent(Intent intent) {
Timber.d("OnNewIntent");
handleIntent(intent);
}
private void handleIntent(Intent intent){
String action = intent.getAction();
String intent_type = intent.getType();
Timber.d("Intent action:" + action + "\n " + "Intent type:" + intent_type);
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
// Handle data from intent.getParcelableExtra()
Timber.d("onNFCDataReaded");
}
// and implementing creating of activity here
}
#Override
protected void onResume() {
super.onResume();
Timber.d("onResume");
enableNFCDispatch();
}
#Override
protected void onPause() {
Timber.d("onPause");
super.onPause();
disableNFCDispatch();
}
#Override
protected void onDestroy() {
super.onDestroy();
Timber.d("OnDestroy");
}
#Override
public void onBackPressed() {
super.onBackPressed();
Timber.d("OnBackPressed");
}
}
Everything works as expected, except for one use case:
When I am opening the application first with Android Beam or an NFC tag, onCreate() is called and it passes getIntent() to handleIntent() with the data received from another phone or an NFC tag. This works fine.
But after that, when I
click onBackPressed button inside MainActivity (i.e. exiting the application), and
then hold the Home button and in the overview screen select my application,
my application is opened again and onCreate() is called again. However, getIntent() returns the old intent with same data (intent.getAction(), intent.getParcelableExtra()) as I got with Android Beam or NFC tag!
I don't understand why! I expect to receive a new intent; the same as if the app is created when I click the application icon.
Can somebody help me with this?
Here is my MainActivity lifecycle:
MainActivity: onCreate
MainActivity: handleIntent
MainActivity: Intent action: android.nfc.action.NDEF_DISCOVERED
Intent type: application/androidbeam
MainActivity: onNFCDataReaded
MainActivity: OnResume
MainActivity: OnBackPressed
MainActivity: onPause
MainActivity: OnDestroy
//After that, I am holding Home Button and selecting my application from
//OverViewScreen, and getting next Log:
MainActivity: onCreate
MainActivity: handleIntent
MainActivity: Intent action:android.nfc.action.NDEF_DISCOVERED
Intent type:application/androidbeam
- // I do not expect it here !!!!!
MainActivity: onNFCDataReaded
MainActivity: OnResume
This is expected behavior. When you bring your activity to the background and later open the activity again from history (long-press home key), Android will recreate the previous activity stack and the activity will be launched with the same parameters as it was opened before. I.e. if it was launched with intent NDEF_DISCOVERED, it will, again, receive that intent.
However, you can easily detect if the activity was launched with the original intent or if it was launched from history. In the latter case, Android adds the flag FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY to the intent. Consequently, you can test for this flag in your handleIntent() method:
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()) ||
NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
...
}
}

Android Custom Launcher startActivity() blocks BOOT_COMPLETED intent

I am currently working on a custom ROM (based on CyanogenMod 11.0), which aims to implement a custom "Kiosk Mode". To do this, I have three components in one application (with system privileges): The service, which handles modifications to the status/navigationbar and disables the power key. The receiver, which only starts the service after the BOOT_COMPLETED signal is received. The HomeIntentWrapper works as the launcher, and only starts one custom activity.
The problem I am currently facing is that the startActivity(...) command in the HomeIntentWrapper somehow blocks the system from booting any further, and the BOOT_COMPLETED intent is never sent.
I verifed this with the adb shell dumpsys activity command, which tells me:
mStartedUsers:
User #0: mState=BOOTING
It also does not show the BOOT_COMPLETED broadcast ever sent.
Now, if the user presses the Home-Button, the BOOT_COMPLETED intent is sent, and the mState switches to RUNNING.
If I do not start an activity in the HomeIntentWrapper, the intent is sent. What am I doing wrong here?
AndroidManifest.xml:
<manifest coreApp="true">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:allowBackup="true"
android:persistent="true" >
<service android:name="Service"
android:process=":service" >
</intent-filter>
</service>
<receiver android:name="Receiver"
android:process=":receiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity android:name="HomeIntentWrapper"
android:process=":launcher" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
Receiver:
public class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, Service.class));
}
}
HomeIntentWrapper:
public class HomeIntentWrapper extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startApp();
}
#Override
protected void onResume() {
super.onResume();
startApp();
}
private void startApp() {
SharedPreferences sharedPrefs = getSharedPreferences(getString(R.string.settings_file), Context.MODE_MULTI_PROCESS);
String customAppIntentString = sharedPrefs.getString(getString(R.string.settings_custom_intent), "");
if(customAppIntentString.equals("") == false) {
try {
Intent intent = Intent.getIntent(customAppIntentString);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} catch(java.net.URISyntaxException e) {
// Intentionally
}
}
}
}
Root cause: finishBooting() is not called because Home Activity is not on top of stack.
http://androidxref.com/4.4.4_r1/xref/frameworks/base/services/java/com/android/server/am/ActivityStackSupervisor.java
Line: 1811
Line: 1883-1886
Line: 1934-1940
Solution:
Do not call start Activity Until Boot_Completed is received.

Android NFC sensing and read tag data at the same time

I have a question about the android NFC.
I have already done the function about read and write, but still have one problem.
I wrote the AAR in my tag, after first sensing, it can launch my application.
Second time sensing (my application is launched), I can read the data from NFC tag.
Is it possible just sensing once that can launch my application and get the data from tag?
Use the below pattern (from here). Summary:
The foreground mode lets you capture scanned tags in the form of intents sent to onNewIntent. An onResume will follow the onNewIntent call, so we'll process the intent there. But onResume can also come from other sources, so we add a boolean variable to make sure we only process each new intent once.
An intent is also present when the activity is launched. By initializing the boolean variable to false, we fit it into the above flow - an your problem should be fixed.
protected boolean intentProcessed = false;
public void onNewIntent(Intent intent) {
Log.d(TAG, "onNewIntent");
// onResume gets called after this to handle the intent
intentProcessed = false;
setIntent(intent);
}
protected void onResume() {
super.onResume();
// your current stuff
if(!intentProcessed) {
intentProcessed = true;
processIntent();
}
}
In AndroidManifest -
<activity
android:name=".TagDiscoverer"
android:alwaysRetainTaskState="true"
android:label="#string/app_name"
android:launchMode="singleInstance"
android:screenOrientation="nosensor" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<action android:name="android.nfc.action.TECH_DISCOVERED" />
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"/>
</activity>
you should initiate the NFC adopter in OnCreate()..
/**
* Initiates the NFC adapter
*/
private void initNfcAdapter() {
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
mPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
}
Now in OnResume() ...
#Override
protected void onResume() {
super.onResume();
if (nfcAdapter != null) {
nfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
}
}

My Broadcast receiver get execute even if my application is not working

My broadcast receiver is Still getting execute even if My application is not working.
as an example I am using android.intent.action.NEW_OUTGOING_CALL to check outgoing call and than i stop music and push notification ..
but even i close my app and kill all task and after if i call than i get notification of my app..
So how do i manage to work my broadcast when i am using my app.
I have crated Service to play music and 2 broadcast receiver file for incoming and outgoing.
Help to solve this problem.
Also How can i destroy my app with service running behind If user press exit button.
**Update I made edited it and its working now fine..thank you so much you all
here is my code
<activity
android:name=".MainActivity"
android:label="#string/title_activity_main"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="OutgoingCallInterceptor">
<intent-filter android:priority="1">
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
<receiver android:name="IncomingCallInterceptor">
<intent-filter android:priority="1">
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.media.AUDIO_BECOMING_NOISY" />
</intent-filter>
</receiver>
Update
as you all suggest me i have made receiver into main class file and register it from there but it wont work
public class MainActivity extends Activity {
RemoteViews layout;
int SDK_INT;
BroadcastReceiver br;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter("android.media.AUDIO_BECOMING_NOISY");
this.registerReceiver(br, filter);
setContentView(R.layout.activity_main);
SDK_INT = android.os.Build.VERSION.SDK_INT;
System.out.println(SDK_INT);
Button start = (Button)findViewById(R.id.play);
Button stop = (Button)findViewById(R.id.stop);
start.setOnClickListener(startListener);
stop.setOnClickListener(stopListener);
br = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if (intent.getAction().equals(android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
context.stopService(new Intent(context, myPlayService.class));
Toast.makeText(context, "Headphones disconnected.", Toast.LENGTH_SHORT).show();
}
} }
};
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(br);
}
an example: how a broadcast reciver can be registered and un registered change as per your need "i hope the code is self explanatory"
private final BroadcastReceiver xyz= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//ur reciver
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter(ACTION);//ur action
this.registerReceiver(xyz, filter);
}
#Override
protected void onDestroy(){
super.onDestroy();
unregisterReceiver(xyz);
}
You need to declare unregisterReceiver() in onResume() or in onpause() methods.
This will solve your problem.
First:
use unregisterReceiver() in onPause() and re-register in onStart().
It's always better to have locally registering the receiver if you want to provide the functionality only when your app is up.
Second:
Use service after binding it and don't call unBind while exiting the app will keep your service alive even after your app is down. I guess you are starting the service locally. Start service by binding it.
Hope this will solve your problem.

Categories

Resources