1

I am quite new in Android: i made some experiments and reserachs on the web, but i didn't figure from where my issue commes... I would like my app to receive the BOOT_COMPLETE broadcast message, but for an unknown reason, i don't acheive to have this working. Sympots are : it seems to work on emulator either at start or using the command

shell am broadcast -a android.intent.action.BOOT_COMPLETED -n <myapp>/.BootReceiver

However, this doesn't work in my "real TV". Even worse: i tryed other applications that uses this broadcast message and they are working (e.g. Aurora, or Launch-on-boot) on both the 'real' TV and the emulator... As their code is open, i check but i didn't found what is wrong in my code... From what i was able to found isung adb on the real TV is that the broadcast is not sent to my application, but is for others:

2020-03-25 17:25:23.800 1796-3309/? I/ActivityManager: Start proc 6054:com.aurora.store/u0a96 for broadcast com.aurora.store/.receiver.BootReceiver
2020-03-25 17:25:26.163 1796-3228/? I/ActivityManager: Start proc 6126:com.github.yeriomin.yalpstore/u0a24 for broadcast com.github.yeriomin.yalpstore/.BootReceiver

Therefore, i would like to request some help, any hint will be welcome...

Here is my manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.eds.testtvapp">

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <uses-feature
        android:name="android.hardware.touchscreen"
        android:required="false" />
    <uses-feature
        android:name="android.software.leanback"
        android:required="true" />

    <application
        android:allowBackup="true"
        android:banner="@mipmap/ic_launcher"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            android:name=".ConfigActivity"
            android:theme="@style/Theme.Leanback">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver
            android:name=".BootReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.REBOOT" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                <action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
                <action android:name="android.intent.action.USER_PRESENT" />
            </intent-filter>
        </receiver>

    </application>
</manifest>

Here the broadcast receiver

package com.eds.testtvapp;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;


public class BootReceiver extends BroadcastReceiver {
    private static final String LOG_TAG = BootReceiver.class.getPackage() + "_" + BootReceiver.class.getSimpleName();

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        Log.i(LOG_TAG, "onReceive");
        if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED) ) {
            Log.i(LOG_TAG, "Start from boot");
            Intent anIntent = new Intent( context, MainActivity.class);
            anIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            //start activity from boot, so do it silently
            Bundle bundle = new Bundle();
            bundle.putBoolean(context.getString(R.string.app_data_start), true);
            anIntent.putExtras(bundle);
            context.startActivity(anIntent);
        }
    }
}

My main activity (the only one)

package com.eds.testtvapp;

import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;

import android.view.View;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.Button;
import android.widget.Toast;
import com.google.android.material.snackbar.Snackbar;

import android.util.Log;


public class MainActivity extends Activity implements
        View.OnClickListener,
        CompoundButton.OnCheckedChangeListener {
    // debugging info
    private static final String LOG_TAG = MainActivity.class.getPackage() + "_" + MainActivity.class.getSimpleName();

    Button mButtonToast;    // button to create a toast
    Button mButtonSnack;    // button to create a snackbar
    Switch mSwitch;         // switch to select toast or snackbar at boot

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.i(LOG_TAG, "Start");
        mButtonToast = findViewById(R.id.button_toast);
        mButtonSnack = findViewById(R.id.button_snack);
        mSwitch = findViewById(R.id.switch_toast_snack);
        boolean bFromBoot = false;
        // retrieve config (or default)
        getPreferencesData();

        // register listeners (after initial set to to avoid switch initialisation to issue a message)
        mSwitch.setOnCheckedChangeListener(this);
        mButtonToast.setOnClickListener(this);
        mButtonSnack.setOnClickListener(this);

        try {
            Bundle bundle = getIntent().getExtras();
            if (bundle!= null) {
                bFromBoot = bundle.getBoolean(getString(R.string.app_data_start));
            }
        } catch (Exception e) {
            Log.e(LOG_TAG, "Error creating main display");
        }
        // if started from boot
        if (bFromBoot) {
            // display something according to settings
            if(mSwitch.isChecked())  {
                Snackbar.make(this.findViewById(android.R.id.content),
                        "Boot Snackbar", Snackbar.LENGTH_LONG).show();
            } else {
                Toast.makeText(this, "Boot Toast", Toast.LENGTH_SHORT)
                        .show();
            }
            // avoid UI to be started
            finish();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        // restore values
        Log.i(LOG_TAG, "Resume");
        getPreferencesData();
    }

    @Override
    protected void onPause() {
        super.onPause();
        // store values
        Log.i(LOG_TAG, "Pause");
        setPreferencesData();
    }

    protected void getPreferencesData() {
        Log.i(LOG_TAG, "Get boot type of message from configuration");
        // Get from the SharedPreferences
        SharedPreferences settings = getApplicationContext().getSharedPreferences(getString(R.string.app_data), MODE_PRIVATE);
        // get saved switch selector value
        String sBootMsgType = settings.getString(getString(R.string.config_switch_selection),getString(R.string.config_switch_Default));
        boolean bBootMsgType = Boolean.parseBoolean(sBootMsgType);
        // sets the UI
        mSwitch.setChecked(bBootMsgType);
    }

    protected void setPreferencesData() {
        Log.i(LOG_TAG, "Sets boot type of message in configuration");
        // Get from the SharedPreferences
        SharedPreferences settings = getApplicationContext().getSharedPreferences(getString(R.string.app_data), MODE_PRIVATE);
        SharedPreferences.Editor editor = settings.edit();
        // get port value and status from UI
        String sBootMsgType = String.valueOf(mSwitch.isChecked());
        // commit the changes
        editor.putString(getString(R.string.config_switch_selection),sBootMsgType);
        editor.apply();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button_toast:
                Toast.makeText(this, "This is a toast", Toast.LENGTH_SHORT)
                        .show();
                break;

            case R.id.button_snack:
                Snackbar.make(this.findViewById(android.R.id.content),
                        "This is a snack", Snackbar.LENGTH_LONG).show();
                break;
        }
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        Log.i(LOG_TAG, "Selector configuration changed");
        switch (buttonView.getId()) {
            case R.id.switch_toast_snack:
                if( isChecked ) {
                    Snackbar.make(this.findViewById(android.R.id.content),
                            "Snackbar used at boot", Snackbar.LENGTH_LONG).show();
                } else {
                    Toast.makeText(this, "Toast used at boot", Toast.LENGTH_SHORT)
                            .show();
                }
                break;
        }
    } // end onCheckedChanged
}

my build.gradle file

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29


    defaultConfig {
        applicationId "com.eds.testtvapp"
        minSdkVersion 24
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.leanback:leanback:1.0.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.material:material:1.1.0'

}

and, just to be complete my styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

<style name="AppTheme" parent="@style/Theme.Leanback" />
</resources>

and strings.xml

<resources>
    <string name="app_name">TestTVApp</string>

    <string name="app_data">APPLICATION_DATA</string>
    <string name="app_data_start">FROM_BOOT</string>
    <string name="config_switch_selection">TOAST_OR_SNACK</string>

    <string name="config_switch_Default">false</string>
</resources>

For what i could see, nothing is (in terms of code) wrong against implementation receiving this broadcast message. Any hint would be welcome..

Thanks!!!

dedalum
  • 11
  • 2

0 Answers0