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.
Related
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.
recently I use BOOT_COMPLETED 2 app (A app, and B app)
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
A app is activity and B app is service app
when my device boot,
first A app launch and B app launch
so, show B app screen.
I want
first B app launch and A app launch showing A app screen
perhaps, Can I give BOOT_COMPLETED Priority is possible?
finally, I want when I boot my device, show A app screen
Thanks!
add
I try
B app(service)
public class BootCompletedReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED) {
Intent i = new Intent("A app package name.BOOT_COMPLETED");
context.sendBroadcast(i);
}
}
}
<receiver android:name=".BootCompletedReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
A app(activity)
public class BootSendReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context,Intent intent) {
if( intent.getAction().equals("B app packagename.BOOT_COMPLETED"));
Intent i = new Intent (context, MainActivity.class);
context.startActivity(i);
}
}
<receiver android:name=".BootSendReceiver">
<intent-filter>
<action android:name="blackeyeonandroid.iosystem.co.kr.simpleserviceexample.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
and I try boot .. but showing B app screen
I think you can not control that..
Instead, you can make APP1 start the APP2. This way, only APP1 receives the BOOT_COMPLETE message. Then, APP1 is responsible to send a new intent to start APP2:
Maybe, you can do as follows (note that APP2 does not receive android's default BOOT_COMPLETED message):
APP1
Manifest:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".AppToStartFirstBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Receiver
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Intent i = new Intent("com.example.mytestapp.BOOT_COMPLETED");
context.sendBroadcast(i);
}
}
APP2
Manifest:
<receiver android:name=".AppToStartLaterBroadcastReceiver">
<intent-filter>
<action android:name="com.example.mytestapp.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Receiver
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("com.example.mytestapp.BOOT_COMPLETED")) {
// Do what you want in secundary APP
}
}
Note
This is an suggestion and you should adjust to your case. Since I don't have more details about your code, you may need to modify it to your case.. But you can use the idea.
I want to develop app that doesn't have icon launcher. The app will run alarmscheduler which triggered when app is installed or phone is rebooted.
The problem is how can I open the activity since the app doesn't have intent filter like below:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Is there a way to handle dial code such as ##4635*#*# to open the activity ?
or any other solutions are welcomed.
You can do it with two ways:
1) as answer by #KishuDroid
2) By define code in manifest
public class MySecretCodeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.provider.Telephony.SECRET_CODE")) {
Intent i = new Intent(context, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
}
In manifest file
<receiver android:name=".MySecretCodeReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SECRET_CODE" />
<data android:scheme="android_secret_code" android:host="4635" />
</intent-filter>
</receiver>
Note:
In Second method you must have to dial *#*#your_code#*#* and dont need to press call button
But in first method you can customise your prefix or postfix of code. For example *#your_code# or **your_code##. but you need to press call button.
You have to use Broadcast Receiver...
public class OutgoingCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if(null == bundle)
return;
String phonenumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.i("OutgoingCallReceiver",phonenumber);
Log.i("OutgoingCallReceiver",bundle.toString());
if(code.equals("#056700") {
intent.setComponent(new ComponentName("com.example", "com.example.yourActivity"));
And Your Android Manifest
<receiver android:name="com.varma.samples.detectcalls.receivers.OutgoingCallReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
Also, include the permission:
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
I want to do something when a headset is plugged in when my app is running in the background. (if possible I want to do it with a broadcast receiver)
I tried the code below:
--ReceiveBroadcast--
package com.example.openmusiconheadsetconnect;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class ReceiveBroadcast extends BroadcastReceiver {
public ReceiveBroadcast() {
}
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"Received!",Toast.LENGTH_LONG).show();
}
}
--Manifest--
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.openmusiconheadsetconnect" >
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver
android:name=".ReceiveBroadcast"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.HEADSET_PLUG" />
</intent-filter>
</receiver>
</application>
</manifest>
Thank you!
Your code is correct, but as far as I know, you cannot put the HEADSET_PLUG filter on the manifest.
Instead, create a receiver in its own class, and make it listen for USER_PRESENT (screen unlocked) or BOOT_COMPLETED in the manifest:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<receiver android:name="classes.myReceiver" >
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
When triggered by such events, your receiver should start the service:
public class myReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context ctx, Intent intent) {
Intent service = new Intent(ctx, VoiceLaunchService.class);
if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)||intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
ctx.startService(service);
}
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
ctx.stopService(service);
}
}
The service will now register the receiver that will be listening to the HEADSET_PLUG intent, in its onCreate method:
#Override
public void onCreate() {
super.onCreate();
speechReconRx=new SpeechReconControlReceiver(this);//"this" will allow you to call service's methods from the receiver
registerReceiver(speechReconRx, new IntentFilter(Intent.HEADSET_PLUG));
}
It's is a hassle, but you'll need it if you don't want to use an activity.
It is google's fault for not letting us put PLUG receivers in the manifest! Finally make the Broadcast that will take action when the headset is plugged in.
public class SpeechReconControlReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context ctx, Intent intent) {
Log.e("joshcsr","HEADSET PLUGGED!");
if(intent.getStringExtra("command")!=null){
c=intent.getStringExtra("command");
}
//run some methods from the service
if (c.equals("resume")) {
sService.resume();
}
if (c.equals("pause")) {
sService.pause();
}
if (c.equals("stop")) {
sService.stop();
}
}
}
To wrap, up you will need:
*A receiver for the BOOT/Screen unlock events.
*A Service to hold everything that will run on the background and to register your headset listening broadcast.
*And a receiver for the headset Plug, that will take action and call methods hosted in the service.
I've did this yesterday, and it works from Jelly bean to Lollipop ...and perhaps even older versions. Cheers.
First you'll need permission to start app in background after boot is completed.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
and also specify this in your broadcast receiver,
<receiver android:name=".YourBroadcastReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
Then create a service that run your application in background, and inside the service use AudioManager.isWiredHeadsetOn() to check if the headset is plugged in. And if so, do the task you want.
while(AudioManager.isWiredHeadsetOn()){
//your task goes here
}
Also add the permission in manifest
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
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.