0

So I am having an issue where I need to be able to determine restart on an HTC device. I can determine ShutDown, but detecting a complete restart seems to be a bit more challenging. After including every possible Android permission and intent-filter I can think of I have come to the conclusion that I must be missing something from HTC. Is there a permission or something that I need from HTC directly to determine phone restarts?

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

....

 <!-- RECEIVERS -->
 <receiver android:name="com.smashingboxes.speed.BootReceiver"
    android:enabled="true" >
    <intent-filter>
         <action android:name="android.intent.action.BOOT_COMPLETED" />
         <action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
         <!-- Just adding this to show that I have tried everything :P -->
         <action android:name="android.intent.action.ACTION_BOOT_COMPLETED" />
    </intent-filter>
 </receiver>
 <receiver android:name="com.smashingboxes.speed.ShutdownReceiver" >
    <intent-filter>
        <action android:name="android.intent.action.ACTION_SHUTDOWN" />
        <action android:name="com.htc.intent.action.QUICKBOOT_POWEROFF" />
    </intent-filter>
</receiver>

Again, ShutdownReceiver is doing it's thing just fine whether it is a restart or a full hard power down/power up. But the BootReceiver is only detecting hard power up's and not HTC's restart. So when I restart I can tell I shut down, but it never detects BOOT_COMPLETED... Any ideas?

zgc7009
  • 3,371
  • 5
  • 22
  • 34

1 Answers1

0

If you can tell on a shutdown event occurs, and since you can subscribe for the "ON-BOOT-COMPLETED" event - why not combine both of them? Save the date on your app SharedPrefernces for the last time a "Shutdown" event happened - after a "On boot completed" event compare the date to the one's saved - if the time difference is lower than (per say) 5 minutes do your "restart" action.

I added a code example which works for me (galaxy S4 running android 4.3) I dont have the main activitis but those are not necessary for your example (just throw a blank one or copy the service and bootloader to yours...) -

manifest -

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.servicelifecycle"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="7"
        android:targetSdkVersion="15" />

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

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".StartedServiceActivity"
            android:label="@string/title_activity_main" >
        </activity>

        <service android:name=".StartedService" >
        </service>
        <service android:name="BoundService" >
        </service>

        <activity android:name="BoundServiceActivity" >
        </activity>
        <activity android:name="MainActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name="BoundedServiceUsingMessangerInterface" >
        </service>

        <activity android:name="MessangerServiceActivity" >
        </activity>
        <activity android:name="IntentServiceActivity" >
        </activity>

        <service android:name="IntentServiceDemo" >
        </service>
        <service android:name="ForeGroundServiceDemo" >
        </service>

        <activity android:name="ForeGroundServiceActivity" >
        </activity>
        <activity android:name=".AIDLActivity" >
        </activity>

        <service
            android:name="BoundedServiceUsingAIDL"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.example.bindservice.AIDL" />
            </intent-filter>
        </service>

        <receiver android:name=".BootCompletedReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

Service -

package com.example.servicelifecycle;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class StartedService extends Service {

    private static final String tag = StartedService.class.getSimpleName();
    Timer timer;
    ToastHandler t;
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        t = new ToastHandler(getApplicationContext());
        t.showToast(tag + " onCreate", 3000);
        Log.d(tag, "onCreate");
        timer = new Timer();
        timer.scheduleAtFixedRate(new RemindTask(), 10000, 6000);
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        t.showToast(tag + " onCreate", 3000);
        Log.d(tag, "onStartCommand startId=" + startId);
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        timer.cancel();

        Log.d(tag, "onDestroy");
        super.onDestroy();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        t.showToast(tag + " onCreate", 3000);
        Log.d(tag, "onUnbind");
        return super.onUnbind(intent);
    }

    class RemindTask extends TimerTask {
        public void run() {
            t.play();
        }
    }

}


BootReciever -

package com.example.servicelifecycle;

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

public class BootCompletedReceiver extends BroadcastReceiver {

    final static String TAG = BootCompletedReceiver.class.getSimpleName();

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.w(TAG, "starting service...");
        context.startService(new Intent(context, StartedService.class));
    }
}


Some example task to be run

package com.example.servicelifecycle;

import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Handler;
import android.widget.Toast;

/**
 * A class for showing a <code>Toast</code> from background processes using a
 * <code>Handler</code>.
 * 
 * @author kaolick
 */
public class ToastHandler {
    // General attributes
    private Context mContext;
    private Handler mHandler;

    /**
     * Class constructor.
     * 
     * @param _context
     *            The <code>Context</code> for showing the <code>Toast</code>
     */
    public ToastHandler(Context _context) {
        this.mContext = _context;
        this.mHandler = new Handler();
    }

    /**
     * Runs the <code>Runnable</code> in a separate <code>Thread</code>.
     * 
     * @param _runnable
     *            The <code>Runnable</code> containing the <code>Toast</code>
     */
    private void runRunnable(final Runnable _runnable) {
        Thread thread = new Thread() {
            public void run() {
                mHandler.post(_runnable);
            }
        };

        thread.start();
        thread.interrupt();
        thread = null;
    }

    /**
     * Shows a <code>Toast</code> using a <code>Handler</code>. Can be used in
     * background processes.
     * 
     * @param _resID
     *            The resource id of the string resource to use. Can be
     *            formatted text.
     * @param _duration
     *            How long to display the message. Only use LENGTH_LONG or
     *            LENGTH_SHORT from <code>Toast</code>.
     */
    public void showToast(final int _resID, final int _duration) {
        final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                // Get the text for the given resource ID
                String text = mContext.getResources().getString(_resID);

                Toast.makeText(mContext, text, _duration).show();
            }
        };

        runRunnable(runnable);
    }

    /**
     * Shows a <code>Toast</code> using a <code>Handler</code>. Can be used in
     * background processes.
     * 
     * @param _text
     *            The text to show. Can be formatted text.
     * @param _duration
     *            How long to display the message. Only use LENGTH_LONG or
     *            LENGTH_SHORT from <code>Toast</code>.
     */
    public void showToast(final CharSequence _text, final int _duration) {
        final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                Toast.makeText(mContext, _text, _duration).show();
            }
        };

        runRunnable(runnable);
    }

    /**
     * Shows a <code>Toast</code> using a <code>Handler</code>. Can be used in
     * background processes.
     * 
     * @param _text
     *            The text to show. Can be formatted text.
     * @param _duration
     *            How long to display the message. Only use LENGTH_LONG or
     *            LENGTH_SHORT from <code>Toast</code>.
     */
    public void play() {
        final Runnable runnable = new Runnable() {

            @Override
            public void run() {
                playSound();
            }
        };

        runRunnable(runnable);
    }

    private void playSound() {
        MediaPlayer mp;
        // mp = MediaPlayer.create(mContext,);
        mp = MediaPlayer.create(mContext, R.raw.click);
        mp.setOnCompletionListener(new OnCompletionListener() {

            @Override
            public void onCompletion(MediaPlayer mp) {
                // TODO Auto-generated method stub
                mp.release();
            }

        });
        mp.setVolume(100, 100);
        mp.start();
    }
}

PS - If you want - send me an email address and Ill send you the whole project.

crazyPixel
  • 2,301
  • 5
  • 24
  • 48
  • The problem is that I don't ever hit BOOT_COMPLETED for my receiver on restart. It can tell that it shuts down, but it doesn't detect it starting back up so the user would have to manually start the application which is the opposite of what i want to do :) – zgc7009 Mar 14 '14 at 15:58
  • Are you sure? You might be doing something wrong - you can use the following tutorial for some guidance - http://khurramitdeveloper.blogspot.co.il/2013/06/start-activity-or-service-on-boot.html I tested that before and you can continue the debug after a restart event - http://stackoverflow.com/questions/7752271/start-debugging-android-application-right-after-reboot The thread above here of the BOOT COMPLETED worked for me.. – crazyPixel Mar 14 '14 at 16:06
  • I am 100% certain. If I shut down the phone using "Power Off" and then start it back up by holding the power button (as most normal Android devices do) then I detect BOOT_COMPLETED. The ONLY time that I don't detect BOOT_COMPLETED is when it has completed boot from restart. So general BOOT_COMPLETED works, this is a specific issue. – zgc7009 Mar 14 '14 at 16:10
  • I added some code exmaple - it works fine with a regualr restart plus a manual restart (shutting down the device than turnning it on) throw a dummy sound in the res > raw file and you should hear a sound. If that dont works than im sorry but im out of ideas... =\ – crazyPixel Mar 14 '14 at 16:24
  • Thank you for the code, but I am still not detecting "regular restart" they are only detecting "manual restart". It just doesn't ever recognize power up on restart. It has to be something in the manifest as that controls how my receivers are actually implemented. A permission or a mislabeled package or something. – zgc7009 Mar 14 '14 at 16:30