In my application service I'm fetch server to get new message.
After found new message my serivce application must be screen on and start activity to display a new message.
In service I don't have problem to resolve data from server, but when screen is off that cause of sleeping service and after start activity, that could not screen on.
activity start by service:
public void onCreate (Bundle savedInstanceState) {
super.onCreate ( savedInstanceState );
requestWindowFeature ( Window.FEATURE_NO_TITLE );
getWindow ().setFlags ( WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN );
PowerManager powermanager = ((PowerManager)getBaseContext ().getSystemService( Context.POWER_SERVICE));
wakeLock=powermanager.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP, "TsmsScreenOn");
wakeLock.acquire ( 10000 );
WindowManager.LayoutParams params = getWindow().getAttributes();
params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.screenBrightness = 1.0f;
getWindow().setAttributes(params);
setContentView ( R.layout.service_view_dialog );
}
My summarized service:
public class ToobaPayamakService extends Service {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onStart(Intent intent, int startId) {
}
private Runnable sendUpdatesToUI = new Runnable() {
};
private void DisplayLoggingInfo() {
}
public int callRequestFromServer(){
if (G.checkInternetConnection ()) {
try {
Cursor c = db.getCursorFirstItemReceived ( username );
c.moveToFirst ();
if (c.moveToFirst ()) {
receive_lastID = c.getString ( c.getColumnIndex ( "lastId" ) );
}
c.close ();
unread = checkWebService ( Integer.valueOf ( receive_lastID ) );
} catch (Exception e) {
e.printStackTrace ();
}
Log.e ( "unread: ", unread + "" );
if (unread != 0) {
G.config_username = username;
G.config_password = password;
try {
G.getRequestFromServerByService ( Long.parseLong ( receive_lastID ), unread, contentResolver );
result_count = unread;
} catch (JSONException e) {
e.printStackTrace ();
}
}
}
return result_count;
}
/* ----------------------------------------------------------------------------------------------------------------- notifyTest */
public void notifyTest ( int unread ) {
Intent i = new Intent ();
i.setClass ( this, ServiceDialog.class );
i.putExtra ( "username", username );
i.putExtra ( "password", password );
i.putExtra ( "unread" , counter );
i.putExtra ( "notify" , notify );
i.setFlags ( Intent.FLAG_ACTIVITY_REORDER_TO_FRONT );
i.setFlags ( Intent.FLAG_ACTIVITY_NEW_TASK );
startActivity ( i );
}
}
The answer is simple: you have to grab a wakelock in your service.
You can also use this flag to keep your screen ON -
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
One more solution using Wakelock -
private PowerManager.WakeLock wl;
Inside onCreate -
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "doneDimScreen");
Inside onPause -
wl.release();
Inside onResume -
wl.acquire();
you have to add this permission as well for the Wakelock to work -
<uses-permission android:name="android.permission.WAKE_LOCK" />
For more detail on Wakelock refer - this
Cheers :)
Related
I am making an app that has both a scanning and advertising functionality as I want to conduct some BLE experiments. But most of the time during the scan I get the device name and UUID as null and there are just flashes for when I am able to see the device that I am advertising with.
The scan feature works fine when I use an app like LightBlue because it constantly shows up in the scan window and the advertisement feature also seems to work fine when I start a scan using the LightBlue app so it is confusing me about what is causing the problem.
I want the scanning feature to detect the device as fast as it can, connect to it and return the details like timestamp, RSSI value etc. of the signal so I can use those values for my experiment. What changes should I do to my following code in order to do that with accuracy?
Here is the advertisement code:
final BluetoothManager bluetoothManagerAdv = (BluetoothManager) getSystemService( Context.BLUETOOTH_SERVICE);
if (bluetoothManagerAdv != null) {
mBluetoothAdapterAdv = bluetoothManagerAdv.getAdapter();
}
mBluetoothAdapterAdv.setName ( "BLE Experiment" );
mBluetoothLeAdvertiser = mBluetoothAdapterAdv.getBluetoothLeAdvertiser();
AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder().setInterval(AdvertisingSetParameters.INTERVAL_HIGH).setTxPowerLevel(AdvertisingSetParameters.TX_POWER_HIGH)
.setConnectable(true).build();
AdvertiseData data = new AdvertiseData.Builder()
.setIncludeDeviceName(false)
.build();
mAdvertiseCallback = new AdvertisingSetCallback () {
#Override
public void onAdvertisingSetStarted(AdvertisingSet advertisingSet,
int txPower,
int status) {
super.onAdvertisingSetStarted (advertisingSet, txPower, status);
}
#Override
public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
Log.e(TAG, "Advertising onStartFailure: ");
super.onAdvertisingSetStopped (advertisingSet);
}
};
mBluetoothLeAdvertiser.startAdvertisingSet(parameters, data, null,null,null, mAdvertiseCallback);
And the scan code:
mIsScanning = true;
ScanSettings.Builder builderScanSettings = new ScanSettings.Builder();
builderScanSettings.setScanMode(ScanSettings.SCAN_MODE_BALANCED);
mBluetoothLeScanner.startScan(null, builderScanSettings.build(), scanCallback);
} else {
enableScanBtn();
mIsScanning = false;
mBluetoothLeScanner.stopScan(scanCallback);
}
}
#RequiresApi(api = Build.VERSION_CODES.O)
private final ScanCallback scanCallback = new ScanCallback () {
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult ( callbackType, result );
if (mList.size () > 0) {
try {
mList.clear ();
mArrayAdapter.clear ();
mArrayAdapter.notifyDataSetChanged ();
rssi = result.getRssi ();
id = Arrays.toString(result.getDevice ().getUuids ());
} catch (final Exception e) {
e.printStackTrace ();
}
}
if (result == null || result.getDevice () == null) {
Log.e ( TAG, "-> No devices found" );
return;
}
try {
name = result.getDevice ().getName ();
time= System.currentTimeMillis();
String apDetails = "AP: " + name + "\n" +
"UUID: " + id + "\n" +
"RSSI: " + rssi + "\n" +
"Time : " + time;
Log.i ( TAG, apDetails );
mList.add ( apDetails );
} catch (NullPointerException e) {
Log.e ( TAG, e.getMessage () );
}
mArrayAdapter = new ArrayAdapter<> ( getApplicationContext (),
android.R.layout.simple_list_item_1, mList );
mListView.setAdapter ( mArrayAdapter );
If you want to see the complete code in the activity : here is the link
I'm working on an app that requires active working service so to avoid Doze Mode I've write code that'll show a default dialog to ask that this app will consume more battery and all. But the main problem here is before showing that dialog app freezes for a second or two and then continue. I'm wondering what is wrong. Here is the code I've written -
private void batteryOptimisationIntent() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Intent intent = new Intent();
String packageName = getPackageName();
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
if (powerManager != null && powerManager.isIgnoringBatteryOptimizations(packageName)) {
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
} else {
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
}
}
}
You call this batteryOptimisationIntent() method in UI thread thats why you UI are freezes.
Please try like this ->
protected void onCreate(Bundle savedInstanceState) {
Runnable runnable = new Runnable() {
#Override
public void run() {
// Your Method name
batteryOptimisationIntent();
}
};
Thread thread = new Thread(runnable);
thread.start();
}
private void batteryOptimisationIntent() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Intent intent = new Intent();
String packageName = getPackageName();
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
if (powerManager != null && powerManager.isIgnoringBatteryOptimizations(packageName)) {
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
} else {
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
}
}
}
I'm trying to make my app download an expansion file. Here's my code so far.
public class main extends Activity implements IDownloaderClient {
TextView tv1;
Button mcButt;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//////////
tv1 = (TextView)findViewById(R.id.textView1);
// Check whether the file have been downloaded.
String mainFileName = Helpers.getExpansionAPKFileName(this, true, 1);
boolean fileExists = Helpers.doesFileExist(this, mainFileName, 32921796L, false);
if (!fileExists) {
Intent launcher = getIntent();
Intent fromNotification = new Intent(this, getClass());
fromNotification.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
fromNotification.setAction(launcher.getAction());
if (launcher.getCategories() != null) {
for (String cat : launcher.getCategories())
{ fromNotification.addCategory(cat); }
}
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, fromNotification, PendingIntent.FLAG_UPDATE_CURRENT);
try {
int result = DownloaderClientMarshaller.startDownloadServiceIfRequired( this, pendingIntent, ExpansionFileDownloaderService.class);
if (DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED != result) {
// implement Downloading UI.
tv1.setText("Need to download.");
return;
}
} catch (Exception e) {
Log.e("apk-expansion-files", "NameNotFoundException occurred. " + e.getMessage(), e);
}
}
tv1.setText("Downloaded!");
}
///////////////////////////////////////////////////
#Override
public void onServiceConnected(Messenger m) {
tv1.setText("onServiceConnected: " + m.toString() );
}
///////////
#Override
public void onDownloadStateChanged(int newState) {
tv1.setText("onDownloadStateChanged: " + String.valueOf(newState) );
}
////////////
#Override
public void onDownloadProgress(DownloadProgressInfo progress) {
ProgressBar mPB = (ProgressBar)findViewById(R.id.progressBar1);
progress.mOverallTotal = progress.mOverallTotal;
mPB.setMax((int) (progress.mOverallTotal >> 8));
mPB.setProgress((int) (progress.mOverallProgress >> 8));
tv1.setText(Long.toString(progress.mOverallProgress * 100 / progress.mOverallTotal) + "%");
tv1.setText(Helpers.getDownloadProgressString(progress.mOverallProgress,progress.mOverallTotal));
}
}
The file does download fine, but it does not trigger onDownloadProgress or onDownloadStateChanged during or after download.
What comes to mind, is that DownloaderClientMarshaller need to be somehow connected with IDownloaderClient which is implemented into the activity...
Any ideas? Thanks!
You should create and stub and connect it to the context. Then, the events will be sent to your IDownloaderClient.
if (DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED != result) {
downloaderClientStub = DownloaderClientMarshaller.CreateStub(this,
YourDownloaderServiceClass.class);
downloaderClientStub.connect(this);
}
I currently have an AsyncTask running that updates the progress bar inside the Activity while downloading a file. The problem is when i leave the Activity and reenters, the ProgressBar will not update anymore.
I tried running the AsyncTask inside a Service but i have no idea how to send the ProgressBar value back to my Activity's UI thread.
I came to the same problem as you did:
I wanted an async task executed (as service)
I wanted to be able to rotate the device, be able to update the UI even if the task finished while the screen was off and I got no notification.
I came up with something like:
public class DatabaseIncompleteActivity extends RoboActivity {
private BroadcastReceiver receiver;
private ProgressDialog progressDialog;
#Inject
private DatabaseSetManager databaseSetManager;
#Inject
private DatabaseDownloadLogger databaseDownloadLogger;
private LocalBroadcastManager localBroadcastManager;
private String jobId;
private static final int ERROR_RETRY_DIALOG = 1;
private static final String ERROR_MESSAGE = "errorMsg";
#Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
localBroadcastManager = LocalBroadcastManager.getInstance( this );
showProgressDialog();
if ( getLastNonConfigurationInstance() == null ) {
startService();
}
}
private void showProgressDialog() {
progressDialog = new ProgressDialog( this );
progressDialog.setMessage( getString( R.string.please_wait ) );
progressDialog.setProgressStyle( ProgressDialog.STYLE_HORIZONTAL );
progressDialog.setIndeterminate( true );
progressDialog.setCancelable( false );
progressDialog.show();
}
private void startService() {
this.jobId = UUID.randomUUID().toString();
Intent intent = new Intent( this, ClientDatabaseDroidService.class );
intent.putExtra( ClientDatabaseDroidService.JOB_ID,
jobId );
intent.putExtra( ClientDatabaseDroidService.INTERACTIVE,
true );
startService( intent );
}
private void registerListenerReceiver() {
if ( receiver != null ) {
return;
}
localBroadcastManager.registerReceiver( this.receiver = new ClientDatabaseBroadcastReceiver(),
new IntentFilter( ClientDatabaseDroidService.PROGRESS_NOTIFICATION ) );
}
#Override
protected void onPause() {
super.onPause();
unregisterListenerReceiver();
}
#Override
protected void onResume() {
super.onResume();
DatabaseDownloadLogEntry logEntry = databaseDownloadLogger.findByJobId( jobId );
// check if service finished while we were not listening
if ( logEntry != null ) {
if ( logEntry.isSuccess() )
onFinish();
else {
Bundle bundle = new Bundle();
bundle.putString( ERROR_MESSAGE,
logEntry.getErrorMessage() );
onError( bundle );
}
return;
}
registerListenerReceiver();
}
#Override
public Object onRetainNonConfigurationInstance() {
return Boolean.TRUE;
}
final class ClientDatabaseBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive( Context context, Intent intent ) {
Bundle extras = intent.getExtras();
int eventType = extras.getInt( ClientDatabaseDroidService.EVENT_TYPE );
switch ( eventType ) {
case ClientDatabaseDroidService.EVENT_TYPE_DOWNLOADING:
onDownloading( extras );
break;
case ClientDatabaseDroidService.EVENT_TYPE_FINISHED:
onFinish();
break;
case ClientDatabaseDroidService.EVENT_TYPE_ERROR:
Bundle bundle = new Bundle();
bundle.putString( ERROR_MESSAGE,
extras.getString( ClientDatabaseDroidService.EXTRA_ERROR_MESSAGE ) );
onError( bundle );
break;
default:
throw new RuntimeException( "should not happen" );
}
}
}
private void unregisterListenerReceiver() {
if ( receiver != null ) {
localBroadcastManager.unregisterReceiver( receiver );
receiver = null;
}
}
private void onError( Bundle extras ) {
progressDialog.dismiss();
showDialog( ERROR_RETRY_DIALOG,
extras );
}
private void onFinish() {
progressDialog.dismiss();
setResult( RESULT_OK );
finish();
}
#Override
protected Dialog onCreateDialog( final int id, Bundle args ) {
if ( id == ERROR_RETRY_DIALOG ) {
Builder builder = new AlertDialog.Builder( this );
builder.setTitle( R.string.error );
builder.setMessage( "" );
builder.setPositiveButton( R.string.yes,
new OnClickListener() {
#Override
public void onClick( DialogInterface dialog, int which ) {
showProgressDialog();
startService();
}
} );
builder.setNegativeButton( R.string.no,
new OnClickListener() {
#Override
public void onClick( DialogInterface dialog, int which ) {
setResult( RESULT_CANCELED );
finish();
}
} );
return builder.create();
}
return super.onCreateDialog( id,
args );
}
#Override
protected void onPrepareDialog( int id, Dialog dialog, Bundle args ) {
if ( id == ERROR_RETRY_DIALOG ) {
( (AlertDialog) dialog ).setMessage( String.format( "%s\n\n%s",
args.getString( ERROR_MESSAGE ),
getString( R.string.do_you_wish_to_retry ) ) );
return;
}
super.onPrepareDialog( id,
dialog );
}
private void onDownloading( Bundle extras ) {
String currentDatabase = extras.getString( ClientDatabaseDroidService.EXTRA_CURRENT_CLASSIFIER );
Progress databaseProgress = extras.getParcelable( ClientDatabaseDroidService.EXTRA_DATABASE_PROGRESS );
Progress downloadProgress = extras.getParcelable( ClientDatabaseDroidService.EXTRA_DOWNLOAD_PROGRESS );
progressDialog.setIndeterminate( false );
progressDialog.setMessage( String.format( "[%d/%d] %s",
databaseProgress.getProcessed(),
databaseProgress.getSize(),
currentDatabase ) );
progressDialog.setProgress( (int) downloadProgress.getProcessed() );
progressDialog.setMax( (int) downloadProgress.getSize() );
}
}
The main idea is:
The activity communicates with service via broadcast. The following events are dispatched from service to UI: download progress (reported each x bytes), download finished, error occured
Each activity start is being assigned a unique job ID which is kept for screen rotation.
Each job result is being persisted into database (or any other persistent storage). This way I can get the job result even if broadcast received was not listening at the moment (screen was off).
hope that helps.
Make in your activity static progress variable
Save progress to preferences
When you re-enter activity grab and set progress from static variable or preferences.
This is normal. Activities die when you leave them or rotate your device. Then they are recreated. AsyncTasks don't relink to the new Activity instance automatically.
Actually, RoboSpice is the library you are looking for : it will allow you to launch a download from an activity, rotate the device, leave the activity, even leave the app, even kill it using the task switcher and your download will survive. Any activity, a new instance of your former activity, or even a completely different one will be able to relink to your download.
You should download the app RoboSpice Motivations from the store, it will explain you why it's not a good idea to use AsyncTasks for networking and show you how to use RoboSpice.
To get a good & fast overview of this problem, please have a look at this infographics.
Also note that if you only download binary data and are not interested in POJOs for instance, then you can use RoboSpice still or the DownloadManager (but it's API is less intuitive than RoboSpice).
I have this code, that goes through steps, aquired from a webservice.
I implemented my own history, so that the user can go back through performed steps.
The problem is that the same step can be visited more than once and that seems to cause my history to fail.
It can go back just fine, but sometimes it takes more than one press on the back button to go to the previous step.
Here's the code for my class that manages history:
private ArrayList<String> idList;
#Override
public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
if ( idList == null )
{
idList = new ArrayList<String>();
}
}
#Override
public void finishFromChild( Activity child )
{
LocalActivityManager manager = getLocalActivityManager();
int index = idList.size()-1;
if ( index < 1 )
{
finish();
return;
}
manager.destroyActivity( idList.get( index ), true );
idList.remove( index ); index--;
String lastId = idList.get( index );
Activity lastActivity = manager.getActivity( lastId );
Intent lastIntent = lastActivity.getIntent();
Window newWindow = manager.startActivity( lastId, lastIntent );
setContentView( newWindow.getDecorView() );
}
public void startChildActivity( String id, Intent intent )
{
id += System.currentTimeMillis();
if ( "restart".equalsIgnoreCase( id ) )
{
idList.clear();
}
Window window = getLocalActivityManager().startActivity( id, intent.addFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP ) );
if ( window != null )
{
idList.add( id );
setContentView( window.getDecorView() );
}
}
public Activity getCurrentActivity()
{
int length = idList.size();
if ( idList.isEmpty() ) {
return null;
}
else
{
return getLocalActivityManager().getActivity( idList.get( length-1 ) );
}
}
#Override
public boolean onKeyDown( int keyCode, KeyEvent event )
{
if ( keyCode == KeyEvent.KEYCODE_BACK )
{
return true;
}
return super.onKeyDown( keyCode, event );
}
#Override
public boolean onKeyUp( int keyCode, KeyEvent event )
{
if ( keyCode == KeyEvent.KEYCODE_BACK )
{
onBackPressed();
return true;
}
return super.onKeyUp( keyCode, event );
}
#Override
public void onBackPressed()
{
int length = idList.size();
if ( length > 1 )
{
Activity current = getLocalActivityManager().getActivity( idList.get( length-1 ) );
current.finish();
}
}
Turns of that the FLAG_ACTIVITY_CLEAR_TOP flag
in my method
public void startChildActivity( String id, Intent intent )
{
id += System.currentTimeMillis();
if ( "restart".equalsIgnoreCase( id ) )
{
idList.clear();
}
Window window = getLocalActivityManager().startActivity( id, intent.addFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP ) );
if ( window != null )
{
idList.add( id );
setContentView( window.getDecorView() );
}
}
Was messing things up, now everything is working perfectly.