How to save state of a progressbar when app is killed? - android

I am building a simple downloader app, with a pause/resume button. When I click on pause button and kill the app the download progress isn't shown anymore, after I open the app again. I want to save the download progress state even if the app is killed. Can anyone help me with this? I'm building the app using download manager pro library from github.
here's the code:
Activity Class:
public class MainActivity extends AppCompatActivity {
String[] permissions = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public static final int REQUEST_ID_MULTIPLE_PERMISSIONS = 100;
EditText edt_url;
Button btn_download;
TextView fileNametv, ProgressbarTv;
private MyDownloadService mService;
ProgressBar progressBar;
String filename, url;
/* UrlFileNameListener listener;*/
Integer progress;
MyReceiver receiver;
public static MainActivity instance;
/* RecyclerView recyclerView;
List<Model> downloadList;
LinearLayoutManager manager;
DownloadAdapter adapter;
// ImageView pausebtn;
int position;*/
File myDirectory;
Boolean mBound = false;
Button pause_btn;
int tasktoken;
/* Model model;
Parcelable mListState;
private final String KEY_RECYCLER_STATE = "recycler_state";
private final String KEY_LIST_STATE = "list_state";*/
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mBound = true;
MyDownloadService.LocalBinder localBinder = (MyDownloadService.LocalBinder) iBinder;
mService = localBinder.getService();
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBound = false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* if(savedInstanceState!=null){
mListState = savedInstanceState.getParcelable(KEY_RECYCLER_STATE);
downloadList =savedInstanceState.getParcelableArrayList(KEY_LIST_STATE);
} */
setContentView(R.layout.activity_main);
edt_url = findViewById(R.id.edt_url);
btn_download = findViewById(R.id.btn_download);
pause_btn = findViewById(R.id.pause_resume);
/*recyclerView = findViewById(R.id.recycler_view);
downloadList = new ArrayList<>();
manager = new LinearLayoutManager(this);
adapter = new DownloadAdapter(downloadList, this);
recyclerView.setLayoutManager(manager);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
manager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);
recyclerView.setAdapter(adapter);*/
fileNametv = findViewById(R.id.download_file_name);
ProgressbarTv = findViewById(R.id.progress_tv);
progressBar = findViewById(R.id.download_progress);
// pausebtn = findViewById(R.id.pause_resume);
instance = this;
/* if (progress!= null && filename != null) {
savedInstanceState.putInt("progress", progress);
savedInstanceState.putString("filename",filename);
// savedInstanceState.putString("filename", model.getFileName());
// savedInstanceState.putParcelable("list",mListState);
}*/
receiver = new MyReceiver();
btn_download.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getDownloadProcess();
}
});
pause_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mService.pauseDownload(tasktoken);
}
});
LocalBroadcastManager.getInstance(this)
.registerReceiver(receiver,
new IntentFilter("download"));
if (checkAndRequestPermissions()) {
myDirectory = new File(Environment.getExternalStorageDirectory() + "/" + "RITSDownloads2");
if (!myDirectory.exists()) {
myDirectory.mkdir();
}
}
}
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this,MyDownloadService.class);
bindService(intent,mServiceConnection,Context.BIND_AUTO_CREATE);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("progress", progress);
outState.putString("filename",filename);
/* mListState = manager.onSaveInstanceState();
outState.putParcelable(KEY_RECYCLER_STATE,mListState);
outState.putParcelableArrayList(KEY_LIST_STATE, (ArrayList<? extends Parcelable>) adapter.getDownloadList());*/
}
#Override
protected void onPause() {
super.onPause();
//mListState = manager.onSaveInstanceState();
}
#Override
protected void onResume() {
super.onResume();
// manager.onRestoreInstanceState(mListState);
}
#Override
public void onBackPressed() {
progress = progressBar.getProgress();
super.onBackPressed();
}
/* #Override
public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onRestoreInstanceState(savedInstanceState, persistentState);
manager.onRestoreInstanceState(mListState);
savedInstanceState.getParcelable(KEY_RECYCLER_STATE);
savedInstanceState.getParcelableArrayList(KEY_LIST_STATE);
}
*/
private void getDownloadProcess() {
url = edt_url.getText().toString();
filename = URLUtil.guessFileName(url, null, null);
//listener.setUrl(url,filename);
edt_url.setText("");
/* model = new Model();
model.setFileName(filename);
downloadList.add(model);
adapter.notifyDataSetChanged();*/
fileNametv.setText(filename);
Intent intent = new Intent(MainActivity.this, MyDownloadService.class);
intent.putExtra("filename", filename);
intent.putExtra("url", url);
intent.setAction(DownloadActions.ACTION.Download_ACTION);
startService(intent);
}
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
progress = intent.getIntExtra("progress", 1);
ReportStructure reportStructure = MyDownloadService.downloadManagerPro.singleDownloadStatus(intent.getIntExtra("tasktoken",1));
tasktoken = intent.getIntExtra("tasktoken",1);
// model.setProgress(progress);
/*int position = downloadList.indexOf(model);
DownloadAdapter.DownloadHolder holder = getDownloadHolder(position);
holder.progressBar.setProgress(progress);*/
progressBar.setProgress(progress);
}
}
/* public DownloadAdapter.DownloadHolder getDownloadHolder(int position) {
return (DownloadAdapter.DownloadHolder) recyclerView.findViewHolderForLayoutPosition(position);
}
*/
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
savedInstanceState.getInt("progress");
savedInstanceState.getString("filename");
/* Log.d("savedInstancestate",savedInstanceState.toString());
//savedInstanceState.getInt("position");
if(savedInstanceState!=null){
List<Model> downloadList = savedInstanceState.getParcelableArrayList(KEY_LIST_STATE);
adapter = new DownloadAdapter(downloadList,this);
}
*/
}
private boolean checkAndRequestPermissions() {
if (ContextCompat.checkSelfPermission(this, permissions[0]) != PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this, permissions[1]) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, permissions, REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
} else {
return true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String permissions[], #NonNull int[] grantResults) {
String TAG = "LOG_PERMISSION";
Log.d(TAG, "Permission callback called-------");
switch (requestCode) {
case REQUEST_ID_MULTIPLE_PERMISSIONS: {
Map<String, Integer> perms = new HashMap<>();
// Initialize the map with both permissions
perms.put(this.permissions[0], PackageManager.PERMISSION_GRANTED);
perms.put(this.permissions[1], PackageManager.PERMISSION_GRANTED);
// Fill with actual results from user
if (grantResults.length > 0) {
for (int i = 0; i < permissions.length; i++)
perms.put(permissions[i], grantResults[i]);
// Check for both permissions
if (perms.get(this.permissions[0]) == PackageManager.PERMISSION_GRANTED
&& perms.get(this.permissions[1]) == PackageManager.PERMISSION_GRANTED
) {
Log.d(TAG, "Phone state and storage permissions granted");
// process the normal flow
//else any one or both the permissions are not granted
//TODO Do your stuff here after permissions granted
} else {
Log.d(TAG, "Some permissions are not granted ask again ");
//permissions is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permissions
// //shouldShowRequestPermissionRationale will return true
//show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
if (ActivityCompat.shouldShowRequestPermissionRationale(this, this.permissions[0]) ||
ActivityCompat.shouldShowRequestPermissionRationale(this, this.permissions[1])) {
showDialogOK("Phone state and storage permissions required for this app",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
checkAndRequestPermissions();
break;
case DialogInterface.BUTTON_NEGATIVE:
// proceed with logic by disabling the related features or quit the app.
break;
}
}
});
}
//permissions is denied (and never ask again is checked)
//shouldShowRequestPermissionRationale will return false
else {
Toast.makeText(this, "Go to settings and enable permissions", Toast.LENGTH_LONG)
.show();
//proceed with logic by disabling the related features or quit the app.
}
}
}
}
}
}
private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", okListener)
.create()
.show();
}
}
Service Class:
public class MyDownloadService extends Service implements DownloadManagerListener {
private static final String LOG_TAG = "tag";
public static DownloadManagerPro downloadManagerPro;
File myDirectory;
int taskToken;
String name;
Intent notificationIntent;
Notification notification;
PendingIntent pendingIntent;
private IBinder binder = new LocalBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(DownloadActions.ACTION.Download_ACTION)) {
Log.d(LOG_TAG, "Received Start Foreground Intent");
}
name = intent.getStringExtra("filename");
final String url = intent.getStringExtra("url");
Log.d(LOG_TAG, name);
Log.d(LOG_TAG, url);
downloadManagerPro = new DownloadManagerPro(this.getApplicationContext());
downloadManagerPro.init("RITSDownloads2/", 16, this);
myDirectory = new File(Environment.getExternalStorageDirectory() + "/" + "RITSDownloads2");
if (!myDirectory.exists()) {
myDirectory.mkdir();
}
taskToken = downloadManagerPro.addTask(name, url, 16, true, true);
Log.d(LOG_TAG, String.valueOf(taskToken));
try {
downloadManagerPro.startDownload(taskToken);
notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(DownloadActions.ACTION.Download_ACTION);
pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification = new NotificationCompat.Builder(this)
.setContentTitle("Downloading")
.setTicker("Rits Download")
.setContentText(name)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(DownloadActions.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
// stopForeground(true);
// stopSelf();
} catch (IOException e) {
e.printStackTrace();
}
return START_STICKY;
}
#Override
public void OnDownloadStarted(long taskId) {
Log.d(LOG_TAG, "DownloadStarted");
}
#Override
public void OnDownloadPaused(long taskId) {
}
#Override
public void onDownloadProcess(long taskId, double percent, long downloadedLength) {
final int progress = (int) percent;
final int taskToken = (int) taskId;
// int position = positions.get(taskToken);
notification = new NotificationCompat.Builder(this)
.setContentTitle("Downloading")
.setTicker("Rits Download")
.setContentText(name)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setContentIntent(pendingIntent)
.setOngoing(true)
.setColor(ContextCompat.getColor(this, R.color.colorPrimary))
.setProgress(100, progress, false)
.build();
startForeground(DownloadActions.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("progress", progress);
intent.setAction("download");
intent.putExtra("tasktoken",taskToken);
ReportStructure structure = downloadManagerPro.singleDownloadStatus(taskToken);
String name =structure.name;
intent.putExtra("name",name);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
}
#Override
public void OnDownloadFinished(long taskId) {
}
#Override
public void OnDownloadRebuildStart(long taskId) {
}
#Override
public void OnDownloadRebuildFinished(long taskId) {
}
public void pauseDownload(int taskToken){
ReportStructure reportStructure = downloadManagerPro.singleDownloadStatus(taskToken);
if(reportStructure.state == TaskStates.DOWNLOADING){
downloadManagerPro.pauseDownload(taskToken);
} else if(reportStructure.state == TaskStates.PAUSED){
try {
downloadManagerPro.startDownload(taskToken);
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void OnDownloadCompleted(long taskId) {
Log.d(LOG_TAG, "Download Complete");
/* MainActivity.instance.pausebtn.post(new Runnable() {
#Override
public void run() {
MainActivity.instance.pausebtn.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_done));
}
});*/
notification = new NotificationCompat.Builder(this)
.setContentTitle("Download Complete")
.setTicker("Rits Download")
.setContentText(name)
.setSmallIcon(R.drawable.ic_action_done)
.setContentIntent(pendingIntent)
.setOngoing(true)
.setColor(ContextCompat.getColor(this, R.color.colorPrimary))
.build();
startForeground(DownloadActions.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
}
#Override
public void connectionLost(long taskId) {
}
#Override
public void onTaskRemoved(Intent rootIntent) {
/* Intent restartService = new Intent(getApplicationContext(),this.getClass());
restartService.setPackage(getPackageName());
PendingIntent restartPendingIntent =PendingIntent.getService(getApplicationContext(), 1,restartService, PendingIntent.FLAG_ONE_SHOT);
AlarmManager myAlarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
myAlarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartPendingIntent);*/
}
public class LocalBinder extends Binder{
public MyDownloadService getService(){
return MyDownloadService.this;
}
}
}

I don't know how you want to save the state but I do know that an activity has a onStop() method that you can override.
The onStop() method runs when the app is killed so I would imagine you would want to do your "saving" in this method.
As for saving something I believe you would want to use the SharedPreferences class. You can find more information about that here.
You can find the lifecycle of an activity here
hope this helps

Save the progress on SharedPreferences onDestroy() and retrieve it from there when activity is created.
Cache:
#Override
protected void onDestroy() {
super.onDestroy();
SharedPreferences sharedPreferences = getSharedPreferences("space_name", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt("progress", progress).apply();
}
And retrieve:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences sharedPreferences = getSharedPreferences("space_name", MODE_PRIVATE);
progress = sharedPreferences.getInt("progress", 0); // 0 default value in case is empty
}

Related

Sinch video call not working in background

I implemented Sinch video calling in my current app. When the app is in the foreground everything is OK for the incoming call. But when I closed the app and tried to receive an incoming call, it does not show any incoming call. How to do video Sinch calling when application is closed for incoming calls? following is my FCMMessageReceiverService class.
public class FCMMessageReceiverService extends FirebaseMessagingService implements ServiceConnection {
Context context;
private SinchService.SinchServiceInterface mSinchServiceInterface;
HashMap dataHashMap;
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
context = this;
if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
Map data = remoteMessage.getData();
dataHashMap = (data instanceof HashMap) ? (HashMap) data : new HashMap<>(data);
if (SinchHelpers.isSinchPushPayload(dataHashMap)) {
getApplicationContext().bindService(new Intent(getApplicationContext(), SinchService.class), this, Context.BIND_AUTO_CREATE);
}
} else {
Intent intent;
PendingIntent pendingIntent = null;
if (remoteMessage.getData().size() > 0) {
String identifier = remoteMessage.getData().get("identifier");
if (identifier.equals("0")) {
intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
notificationBuilder.setWhen(System.currentTimeMillis());
notificationBuilder.setContentTitle(remoteMessage.getNotification().getTitle());
notificationBuilder.setContentText(remoteMessage.getNotification().getBody());
notificationBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
notificationBuilder.setDefaults(Notification.DEFAULT_ALL | Notification.DEFAULT_LIGHTS | Notification.FLAG_SHOW_LIGHTS | Notification.DEFAULT_SOUND);
notificationBuilder.setAutoCancel(true);
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher);
notificationBuilder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
}
public static boolean foregrounded() {
ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
ActivityManager.getMyMemoryState(appProcessInfo);
return (appProcessInfo.importance == appProcessInfo.IMPORTANCE_FOREGROUND || appProcessInfo.importance == appProcessInfo.IMPORTANCE_VISIBLE);
}
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
if (SinchService.class.getName().equals(componentName.getClassName())) {
mSinchServiceInterface = (SinchService.SinchServiceInterface) iBinder;
}
// it starts incoming call activity which does not show incoming caller name and picture
NotificationResult result = mSinchServiceInterface.relayRemotePushNotificationPayload(dataHashMap);
if (result.isValid() && result.isCall()) {
CallNotificationResult callResult = result.getCallResult();
if (callResult.isCallCanceled() || callResult.isTimedOut()) {
createNotification("Missed Call from : ", callResult.getRemoteUserId());
return;
} else {
if (callResult.isVideoOffered()) {
Intent intent = new Intent(this, IncomingCallScreenActivity.class);
intent.putExtra(SinchService.CALL_ID, callResult.getRemoteUserId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
}
}
} else if (result.isValid() && result.isMessage()) {
//i want to get message content here
MessageNotificationResult notificationResult = result.getMessageResult();
createNotification("Received Message from : ", notificationResult.getSenderId());
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
unbindService(this);
}
private void createNotification(String contentTitle, String userId) {
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(getApplicationContext(), MainActivity.class), 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext()).setSmallIcon(R.mipmap.ic_launcher).setContentTitle(contentTitle).setContentText(userId);
mBuilder.setContentIntent(contentIntent);
mBuilder.setDefaults(Notification.DEFAULT_SOUND);
mBuilder.setAutoCancel(true);
NotificationManager mNotificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, mBuilder.build());
}
}
here is my since service code:
public class SinchService extends Service {
private static final String APP_KEY = "***********";
private static final String APP_SECRET = "***********";
private static final String ENVIRONMENT = "clientapi.sinch.com";
public static final String CALL_ID = "CALL_ID";
static final String TAG = SinchService.class.getSimpleName();
private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient;
private String mUserId;
private PersistedSettings mSettings;
private StartFailedListener mListener;
#Override
public void onCreate() {
super.onCreate();
mSettings = new PersistedSettings(getApplicationContext());
String userName = mSettings.getUsername();
if (!userName.isEmpty()) {
Intent intent=new Intent(this,placecallActvity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
start(userName);
}
}
#Override
public void onDestroy() {
if (mSinchClient != null && mSinchClient.isStarted()) {
mSinchClient.terminate();
}
super.onDestroy();
}
private void start(String userName) {
if (mSinchClient == null) {
mSettings.setUsername(userName);
mUserId = userName;
mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(userName).applicationKey(APP_KEY).applicationSecret(APP_SECRET).environmentHost(ENVIRONMENT).build();
mSinchClient.setSupportCalling(true);
mSinchClient.setSupportManagedPush(true);
mSinchClient.checkManifest();
mSinchClient.setSupportActiveConnectionInBackground(true);
mSinchClient.startListeningOnActiveConnection();
mSinchClient.addSinchClientListener(new MySinchClientListener());
mSinchClient.getCallClient().setRespectNativeCalls(false);
mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
mSinchClient.getVideoController().setResizeBehaviour(VideoScalingType.ASPECT_FILL);
mSinchClient.start();
}
}
private void stop() {
if (mSinchClient != null) {
mSinchClient.terminate();
mSinchClient = null;
}
mSettings.setUsername("");
}
private boolean isStarted() {
return (mSinchClient != null && mSinchClient.isStarted());
}
#Override
public IBinder onBind(Intent intent) {
return mSinchServiceInterface;
}
public class SinchServiceInterface extends Binder {
public Call callUserVideo(String userId) {
return mSinchClient.getCallClient().callUserVideo(userId);
}
public NotificationResult relayRemotePushNotificationPayload(final Map payload) {
if (mSinchClient == null && !mSettings.getUsername().isEmpty()) {
start(mSettings.getUsername());
} else if (mSinchClient == null && mSettings.getUsername().isEmpty()) {
return null;
}
return mSinchClient.relayRemotePushNotificationPayload(payload);
}
public String getUserName() {
return mUserId;
}
public boolean isStarted() {
return SinchService.this.isStarted();
}
public void startClient(String userName) {
start(userName);
}
public void stopClient() {
stop();
}
public void setStartListener(StartFailedListener listener) {
mListener = listener;
}
public Call getCall(String callId) {
return mSinchClient.getCallClient().getCall(callId);
}
public VideoController getVideoController() {
if (!isStarted()) {
return null;
}
return mSinchClient.getVideoController();
}
public AudioController getAudioController() {
if (!isStarted()) {
return null;
}
return mSinchClient.getAudioController();
}
}
public interface StartFailedListener {
void onStartFailed(SinchError error);
void onStarted();
}
private class MySinchClientListener implements SinchClientListener {
#Override
public void onClientFailed(SinchClient client, SinchError error) {
if (mListener != null) {
mListener.onStartFailed(error);
}
mSinchClient.terminate();
mSinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
Log.d(TAG, "SinchClient started");
if (mListener != null) {
mListener.onStarted();
}
}
#Override
public void onClientStopped(SinchClient client) {
Log.d(TAG, "SinchClient stopped");
}
#Override
public void onLogMessage(int level, String area, String message) {
switch (level) {
case Log.DEBUG:
Log.d(area, message);
break;
case Log.ERROR:
Log.e(area, message);
break;
case Log.INFO:
Log.i(area, message);
break;
case Log.VERBOSE:
Log.v(area, message);
break;
case Log.WARN:
Log.w(area, message);
break;
}
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client,
ClientRegistration clientRegistration) {
}
}
private class SinchCallClientListener implements CallClientListener {
#Override
public void onIncomingCall(CallClient callClient, Call call) {
Log.d(TAG, "Incoming call");
Intent intent = new Intent(SinchService.this, IncomingCallScreenActivity.class);
intent.putExtra(CALL_ID, call.getCallId());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
SinchService.this.startActivity(intent);
}
}
private class PersistedSettings {
private SharedPreferences mStore;
private static final String PREF_KEY = "Sinch";
public PersistedSettings(Context context) {
mStore = context.getSharedPreferences(PREF_KEY, MODE_PRIVATE);
}
public String getUsername() {
return mStore.getString("Username", "");
}
public void setUsername(String username) {
SharedPreferences.Editor editor = mStore.edit();
editor.putString("Username", username);
editor.commit();
}
}
}
add FCM to your project
add following code
public class SinchService extends Service {
static final String APP_KEY = "************";
static final String APP_SECRET = "***********";
static final String ENVIRONMENT = "clientapi.sinch.com";
public static final int MESSAGE_PERMISSIONS_NEEDED = 1;
public static final String REQUIRED_PERMISSION = "REQUIRED_PESMISSION";
public static final String MESSENGER = "MESSENGER";
private Messenger messenger;
public static final String CALL_ID = "CALL_ID";
static final String TAG = SinchService.class.getSimpleName();
private SinchServiceInterface mSinchServiceInterface = new SinchServiceInterface();
private SinchClient mSinchClient;
private String mUserId;
private StartFailedListener mListener;
private PersistedSettings mSettings;
private AudioPlayer audioPlayer;
private Handler handler;
#Override
public void onCreate() {
super.onCreate();
super.onCreate();
mSettings = new PersistedSettings(getApplicationContext());
String userName = mSettings.getUsername();
if (!userName.isEmpty()) {
start(userName);
}
handler = new Handler();
}
private void createClient(String username) {
mSinchClient = Sinch.getSinchClientBuilder().context(getApplicationContext()).userId(username)
.applicationKey(APP_KEY)
.applicationSecret(APP_SECRET)
.environmentHost(ENVIRONMENT).build();
mSinchClient.setSupportCalling(true);
mSinchClient.setSupportManagedPush(true);
mSinchClient.addSinchClientListener(new MySinchClientListener());
mSinchClient.getCallClient().addCallClientListener(new SinchCallClientListener());
mSinchClient.setPushNotificationDisplayName("User " + username);
}
#Override
public void onDestroy() {
if (mSinchClient != null && mSinchClient.isStarted()) {
mSinchClient.terminateGracefully();
}
super.onDestroy();
}
private boolean hasUsername() {
if (mSettings.getUsername().isEmpty()) {
Log.e(TAG, "Can't start a SinchClient as no username is available!");
return false;
}
return true;
}
private void createClientIfNecessary() {
if (mSinchClient != null)
return;
if (!hasUsername()) {
throw new IllegalStateException("Can't create a SinchClient as no username is available!");
}
createClient(mSettings.getUsername());
}
private void start(String userName) {
boolean permissionsGranted = true;
if (mSinchClient == null) {
mSettings.setUsername(userName);
createClient(userName);
}
createClientIfNecessary();
try {
//mandatory checks
mSinchClient.checkManifest();
if (getApplicationContext().checkCallingOrSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
throw new MissingPermissionException(Manifest.permission.CAMERA);
}
} catch (MissingPermissionException e) {
permissionsGranted = false;
if (messenger != null) {
Message message = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString(REQUIRED_PERMISSION, e.getRequiredPermission());
message.setData(bundle);
message.what = MESSAGE_PERMISSIONS_NEEDED;
try {
messenger.send(message);
} catch (RemoteException e1) {
e1.printStackTrace();
}
}
}
if (permissionsGranted) {
Log.d(TAG, "Starting SinchClient");
try {
mSinchClient.start();
} catch (IllegalStateException e) {
Log.w(TAG, "Can't start SinchClient - " + e.getMessage());
}
}
}
private void stop() {
if (mSinchClient != null) {
mSinchClient.terminateGracefully();
mSinchClient = null;
}
}
private boolean isStarted() {
return (mSinchClient != null && mSinchClient.isStarted());
}
#Override
public IBinder onBind(Intent intent) {
messenger = intent.getParcelableExtra(MESSENGER);
return mSinchServiceInterface;
}
public class SinchServiceInterface extends Binder {
public Call callUserVideo(String userId) {
return mSinchClient.getCallClient().callUserVideo(userId);
}
public String getUserName() {
return mSettings.getUsername();
}
public void setUsername(String username) {
mSettings.setUsername(username);
}
public void retryStartAfterPermissionGranted() {
SinchService.this.attemptAutoStart();
}
public boolean isStarted() {
return SinchService.this.isStarted();
}
public void startClient(String userName) {
start(userName);
}
public void stopClient() {
stop();
}
public void setStartListener(StartFailedListener listener) {
mListener = listener;
}
public Call getCall(String callId) {
return mSinchClient.getCallClient().getCall(callId);
}
public VideoController getVideoController() {
if (!isStarted()) {
return null;
}
return mSinchClient.getVideoController();
}
public AudioController getAudioController() {
if (!isStarted()) {
return null;
}
return mSinchClient.getAudioController();
}
public NotificationResult relayRemotePushNotificationPayload(final Map payload) {
if (!hasUsername()) {
Log.e(TAG, "Unable to relay the push notification!");
return null;
}
createClientIfNecessary();
return mSinchClient.relayRemotePushNotificationPayload(payload);
}
}
private void attemptAutoStart() {
}
public interface StartFailedListener {
void onStartFailed(SinchError error);
void onStarted();
}
private class MySinchClientListener implements SinchClientListener {
#Override
public void onClientFailed(SinchClient client, SinchError error) {
if (mListener != null) {
mListener.onStartFailed(error);
}
mSinchClient.terminate();
mSinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
Log.d(TAG, "SinchClient started");
if (mListener != null) {
mListener.onStarted();
}
}
#Override
public void onClientStopped(SinchClient client) {
Log.d(TAG, "SinchClient stopped");
}
#Override
public void onLogMessage(int level, String area, String message) {
switch (level) {
case Log.DEBUG:
Log.d(area, message);
break;
case Log.ERROR:
Log.e(area, message);
break;
case Log.INFO:
Log.i(area, message);
break;
case Log.VERBOSE:
Log.v(area, message);
break;
case Log.WARN:
Log.w(area, message);
break;
}
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client,
ClientRegistration clientRegistration) {
}
}
private class SinchCallClientListener implements CallClientListener {
#Override
public void onIncomingCall(CallClient callClient, Call call) {
Log.d(TAG, "onIncomingCall: " + call.getCallId());
audioPlayer = AudioPlayer.getInstance(getApplicationContext());
call.addCallListener(new SinchCallListener());
Intent intent = new Intent(SinchService.this, IncomingCallScreenActivity.class);
intent.putExtra(EXTRA_ID, MESSAGE_ID);
intent.putExtra(CALL_ID, call.getCallId());
boolean inForeground = isAppOnForeground(getApplicationContext());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (inForeground) {
SinchService.this.startActivity(intent);
} else {
if (!audioPlayer.isPlayedRingtone()) {
audioPlayer.playRingtone();
}
((NotificationManager) Objects.requireNonNull(getSystemService(NOTIFICATION_SERVICE))).notify(MESSAGE_ID, createIncomingCallNotification(call.getRemoteUserId(), intent));
}
}
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = null;
if (activityManager != null) {
appProcesses = activityManager.getRunningAppProcesses();
}
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
private Bitmap getBitmap(Context context, int resId) {
int largeIconWidth = (int) context.getResources()
.getDimension(R.dimen.height);
int largeIconHeight = (int) context.getResources()
.getDimension(R.dimen.height);
Drawable d = context.getResources().getDrawable(resId);
Bitmap b = Bitmap.createBitmap(largeIconWidth, largeIconHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
d.setBounds(0, 0, largeIconWidth, largeIconHeight);
d.draw(c);
return b;
}
private PendingIntent getPendingIntent(Intent intent, String action) {
intent.setAction(action);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 111, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
#TargetApi(29)
private Notification createIncomingCallNotification(String userId, Intent fullScreenIntent) {
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 112, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(getApplicationContext(), FcmListenerService.CHANNEL_ID)
.setContentTitle("Incoming call")
.setContentText(userId)
.setLargeIcon(getBitmap(getApplicationContext(), R.drawable.call_normal))
.setSmallIcon(R.drawable.call_pressed)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentIntent(pendingIntent)
.setFullScreenIntent(pendingIntent, true)
.addAction(R.drawable.button_accept, "Answer", getPendingIntent(fullScreenIntent, ACTION_ANSWER))
.addAction(R.drawable.button_decline, "Ignore", getPendingIntent(fullScreenIntent, ACTION_IGNORE))
.setOngoing(true);
return builder.build();
}
}
private class SinchCallListener implements CallListener {
#Override
public void onCallEnded(Call call) {
cancelNotification();
if (audioPlayer != null && audioPlayer.isPlayedRingtone()) {
audioPlayer.stopRingtone();
}
}
#Override
public void onCallEstablished(Call call) {
Log.d(TAG, "Call established");
if (audioPlayer != null && audioPlayer.isPlayedRingtone()) {
audioPlayer.stopRingtone();
}
}
#Override
public void onCallProgressing(Call call) {
Log.d(TAG, "Call progressing");
}
#Override
public void onShouldSendPushNotification(Call call, List<PushPair> pushPairs) {
// no need to implement for managed push
}
}
public void cancelNotification() {
NotificationManager nMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (nMgr != null) {
nMgr.cancel(MESSAGE_ID);
}
}
private static class PersistedSettings {
private SharedPreferences mStore;
private static final String PREF_KEY = "Sinch";
public PersistedSettings(Context context) {
mStore = context.getSharedPreferences(PREF_KEY, MODE_PRIVATE);
}
public String getUsername() {
return mStore.getString("Username", "");
}
public void setUsername(String username) {
SharedPreferences.Editor editor = mStore.edit();
editor.putString("Username", username);
editor.apply();
}
}
}
and crete FcmListenerService and add following code
public class FcmListenerService extends FirebaseMessagingService {
public static String CHANNEL_ID = "Sinch Push Notification Channel";
private final String PREFERENCE_FILE = "com.sinch.android.rtc.sample.push.shared_preferences";
SharedPreferences sharedPreferences;
#Override
public void onMessageReceived(RemoteMessage remoteMessage){
Map data = remoteMessage.getData();
if (SinchHelpers.isSinchPushPayload(data)) {
new ServiceConnection() {
private Map payload;
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Context context = getApplicationContext();
sharedPreferences = context.getSharedPreferences(PREFERENCE_FILE, Context.MODE_PRIVATE);
if (payload != null) {
SinchService.SinchServiceInterface sinchService = (SinchService.SinchServiceInterface) service;
if (sinchService != null) {
NotificationResult result = sinchService.relayRemotePushNotificationPayload(payload);
// handle result, e.g. show a notification or similar
// here is example for notifying user about missed/canceled call:
if (result!=null && result.isValid() && result.isCall()) {
CallNotificationResult callResult = result.getCallResult();
if (callResult != null && result.getDisplayName() != null) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(callResult.getRemoteUserId(), result.getDisplayName());
editor.apply();
}
if (callResult != null && callResult.isCallCanceled()) {
String displayName = result.getDisplayName();
if (displayName == null) {
displayName = sharedPreferences.getString(callResult.getRemoteUserId(), "n/a");
}
createMissedCallNotification(!displayName.isEmpty() ? displayName : callResult.getRemoteUserId());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
context.deleteSharedPreferences(PREFERENCE_FILE);
}
}
}
}
}
payload = null;
}
#Override
public void onServiceDisconnected(ComponentName name) {}
public void relayMessageData(Map<String, String> data) {
payload = data;
createNotificationChannel(NotificationManager.IMPORTANCE_MAX);
getApplicationContext().bindService(new Intent(getApplicationContext(), SinchService.class), this, BIND_AUTO_CREATE);
}
}.relayMessageData(data);
}
}
private void createNotificationChannel(int importance) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Amar LPG";
String description = "Incoming call notification";
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
}
}
private void createMissedCallNotification(String userId) {
createNotificationChannel(NotificationManager.IMPORTANCE_DEFAULT);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0,
new Intent(getApplicationContext(), IncomingCallScreenActivity.class), 0);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID)
.setSmallIcon(R.drawable.icon)
.setContentTitle("Missed call from ")
.setContentText(userId)
.setContentIntent(contentIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
if (mNotificationManager != null) {
mNotificationManager.notify(1, builder.build());
}
}
}
in the incoming call screen add the following code
public class IncomingCallScreenActivity extends BaseActivity {
static final String TAG = IncomingCallScreenActivity.class.getSimpleName();
private String mCallId;
private AudioPlayer mAudioPlayer;
public static final String ACTION_ANSWER = "answer";
public static final String ACTION_IGNORE = "ignore";
public static final String EXTRA_ID = "id";
public static int MESSAGE_ID = 14;
private String mAction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_incoming_call_screen);
Button answer = (Button) findViewById(R.id.answerButton);
answer.setOnClickListener(mClickListener);
Button decline = (Button) findViewById(R.id.declineButton);
decline.setOnClickListener(mClickListener);
mAudioPlayer = new AudioPlayer(this);
mAudioPlayer.playRingtone();
mCallId = getIntent().getStringExtra(SinchService.CALL_ID);
mAction = "";
}
#Override
protected void onResume() {
super.onResume();
Intent intent = getIntent();
if (intent != null) {
if (intent.getStringExtra(SinchService.CALL_ID) != null) {
mCallId = getIntent().getStringExtra(SinchService.CALL_ID);
}
final int id = intent.getIntExtra(EXTRA_ID, -1);
if (id > 0) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(id);
}
mAction = intent.getAction();
}
}
#Override
protected void onServiceConnected() {
Call call = getSinchServiceInterface().getCall(mCallId);
if (call != null) {
call.addCallListener(new SinchCallListener());
TextView remoteUser = (TextView) findViewById(R.id.remoteUser);
remoteUser.setText(call.getRemoteUserId());
if (ACTION_ANSWER.equals(mAction)) {
mAction = "";
answerClicked();
} else if (ACTION_IGNORE.equals(mAction)) {
mAction = "";
declineClicked();
}
} else {
Log.e(TAG, "Started with invalid callId, aborting");
finish();
}
}
private void answerClicked() {
if (mAudioPlayer!=null && mAudioPlayer.isPlayedRingtone()){
mAudioPlayer.stopRingtone();
}
Call call = getSinchServiceInterface().getCall(mCallId);
if (call != null) {
Log.d(TAG, "Answering call");
call.answer();
Intent intent = new Intent(this, CallScreenActivity.class);
intent.putExtra(SinchService.CALL_ID, mCallId);
startActivity(intent);
} else {
finish();
}
}
private void declineClicked() {
if (mAudioPlayer!=null && mAudioPlayer.isPlayedRingtone()){
mAudioPlayer.stopRingtone();
}
Call call = getSinchServiceInterface().getCall(mCallId);
if (call != null) {
call.hangup();
}
finish();
}
private class SinchCallListener implements VideoCallListener {
#Override
public void onCallEnded(Call call) {
CallEndCause cause = call.getDetails().getEndCause();
Log.d(TAG, "Call ended, cause: " + cause.toString());
mAudioPlayer.stopRingtone();
finish();
}
#Override
public void onCallEstablished(Call call) {
Log.d(TAG, "Call established");
}
#Override
public void onCallProgressing(Call call) {
Log.d(TAG, "Call progressing");
}
#Override
public void onShouldSendPushNotification(Call call, List<PushPair> pushPairs) {
}
#Override
public void onVideoTrackAdded(Call call) {
// Display some kind of icon showing it's a video call
}
#Override
public void onVideoTrackPaused(Call call) {
}
#Override
public void onVideoTrackResumed(Call call) {
}
}
private View.OnClickListener mClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.answerButton:
answerClicked();
break;
case R.id.declineButton:
declineClicked();
break;
}
}
};
}
in the login activity add the following code.
public class MainActivity extends BaseActivity implements SinchService.StartFailedListener, PushTokenRegistrationCallback, UserRegistrationCallback {
private Button mLoginButton;
private EditText mLoginName;
private ProgressDialog mSpinner;
private String mUserId;
private long mSigningSequence = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA, Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.READ_PHONE_STATE},100);
}
mLoginName = (EditText) findViewById(R.id.loginName);
mLoginButton = (Button) findViewById(R.id.loginButton);
mLoginButton.setEnabled(false);
mLoginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
loginClicked();
}
});
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onServiceConnected() {
mLoginButton.setEnabled(true);
getSinchServiceInterface().setStartListener(this);
}
#Override
protected void onPause() {
if (mSpinner != null) {
mSpinner.dismiss();
}
super.onPause();
}
#Override
public void onStartFailed(SinchError error) {
Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show();
if (mSpinner != null) {
mSpinner.dismiss();
}
}
#Override
public void onStarted() {
openPlaceCallActivity();
}
private void loginClicked() {
String userName = mLoginName.getText().toString();
if (userName.isEmpty()) {
Toast.makeText(this, "Please enter a name", Toast.LENGTH_LONG).show();
return;
}
if (!getSinchServiceInterface().isStarted()) {
getSinchServiceInterface().startClient(userName);
showSpinner();
} else {
openPlaceCallActivity();
}
mUserId = userName;
UserController uc = Sinch.getUserControllerBuilder()
.context(getApplicationContext())
.applicationKey(APP_KEY)
.userId(mUserId)
.environmentHost(ENVIRONMENT)
.build();
uc.registerUser(this, this);
}
private void openPlaceCallActivity() {
Intent mainActivity = new Intent(this, PlaceCallActivity.class);
startActivity(mainActivity);
finish();
}
private void showSpinner() {
mSpinner = new ProgressDialog(this);
mSpinner.setTitle("Logging in");
mSpinner.setMessage("Please wait...");
mSpinner.show();
}
private void dismissSpinner() {
if (mSpinner != null) {
mSpinner.dismiss();
mSpinner = null;
}
}
#Override
public void tokenRegistered() {
dismissSpinner();
startClientAndOpenPlaceCallActivity();
}
private void startClientAndOpenPlaceCallActivity() {
// start Sinch Client, it'll result onStarted() callback from where the place call activity will be started
if (!getSinchServiceInterface().isStarted()) {
getSinchServiceInterface().startClient("");
showSpinner();
}
}
#Override
public void tokenRegistrationFailed(SinchError sinchError) {
dismissSpinner();
Toast.makeText(this, "Push token registration failed - incoming calls can't be received!", Toast.LENGTH_LONG).show();
}
#Override
public void onCredentialsRequired(ClientRegistration clientRegistration) {
String toSign = mUserId + APP_KEY + mSigningSequence + APP_SECRET;
String signature;
MessageDigest messageDigest;
try {
messageDigest = MessageDigest.getInstance("SHA-1");
byte[] hash = messageDigest.digest(toSign.getBytes("UTF-8"));
signature = Base64.encodeToString(hash, Base64.DEFAULT).trim();
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e.getCause());
}
clientRegistration.register(signature, mSigningSequence++);
}
#Override
public void onUserRegistered() {
}
#Override
public void onUserRegistrationFailed(SinchError sinchError) {
dismissSpinner();
Toast.makeText(this, "Registration failed!", Toast.LENGTH_LONG).show();
}
}
on our SDK package you will find under the Samples folder multiple sample files, the one called sinch-rtc-sample-video-push does what you wnat.
You should also check our docs here:
https://developers.sinch.com/docs/voice-android-push-notifications
Best regards

Google Fit can't be read in background?

I am trying to read Google Fit data in my app. I have written the code and it works great. I created an AlarmMangaer and put the fit data read in there but it seems like even though the alarm is being called, the fit data is not read unless the app is open and in the foreground. Here is the code I have:
public class MainActivity extends AppCompatActivity implements OnDataPointListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private static final int REQUEST_OAUTH = 1;
private static final String TAG = "FITTEST";
AlarmManager alarmMgr;
PendingIntent pendingIntent;
private static final String AUTH_PENDING = "auth_state_pending";
private boolean authInProgress = false;
public static GoogleApiClient mClient = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
authInProgress = savedInstanceState.getBoolean(AUTH_PENDING);
}
buildFitnessClient();
}
private void buildFitnessClient() {
// Create the Google API Client
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addConnectionCallbacks(this)
.enableAutoManage(this, 0, this)
.build();
}
#Override
protected void onStart() {
super.onStart();
// Connect to the Fitness API
Log.i(TAG, "Connecting...");
mClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mClient.isConnected()) {
mClient.disconnect();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_OAUTH) {
authInProgress = false;
if (resultCode == RESULT_OK) {
// Make sure the app is not already connected or attempting to connect
if (!mClient.isConnecting() && !mClient.isConnected()) {
mClient.connect();
}
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
private void registerFitnessDataListener(DataSource dataSource, DataType dataType) {
SensorRequest request = new SensorRequest.Builder()
.setDataSource( dataSource )
.setDataType( dataType )
.setSamplingRate( 3, TimeUnit.SECONDS )
.build();
Fitness.SensorsApi.add( mClient, request, (OnDataPointListener) this)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.e( "GoogleFit", "SensorApi successfully added" );
}
}
});
}
#Override
public void onDataPoint(DataPoint dataPoint) {
for( final Field field : dataPoint.getDataType().getFields() ) {
final Value value = dataPoint.getValue( field );
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "Field: " + field.getName() + " Value: " + value, Toast.LENGTH_SHORT).show();
}
});
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Toast.makeText(this, "OnConnected", Toast.LENGTH_SHORT).show();
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
startAlarmManager();
}
public void startAlarmManager() {
Intent dialogIntent = new Intent(getBaseContext(), AlarmReceiver.class);
alarmMgr = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
pendingIntent = PendingIntent.getBroadcast(this, 0, dialogIntent,PendingIntent.FLAG_CANCEL_CURRENT);
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(), 10000, pendingIntent);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
Here is the Alarm Service:
public class AlarmReceiver extends BroadcastReceiver {
String steps = "";
private GoogleApiClient mGoogleApiClient = MainActivity.mClient;
private Context mContext;
#Override
public void onReceive(Context context, Intent intent) {
this.mContext = context;
Log.d("ALARM", "JR Alarm Service running");
sendNotification("JR Fitness Alarm!!");
new ViewTodaysStepCountTask().execute();
}
private void displayStepDataForToday() {
if (mGoogleApiClient != null ) {
DailyTotalResult result = Fitness.HistoryApi.readDailyTotal(mGoogleApiClient, DataType.TYPE_STEP_COUNT_DELTA).await(1, TimeUnit.MINUTES);
showDataSet(result.getTotal());
} else {
Toast.makeText(mContext, "Google Client Empty", Toast.LENGTH_SHORT).show();
}
}
private void showDataSet(DataSet dataSet) {
Log.e("History", "Data returned for Data type: " + dataSet.getDataType().getName());
DateFormat dateFormat = DateFormat.getDateInstance();
DateFormat timeFormat = DateFormat.getTimeInstance();
for (DataPoint dp : dataSet.getDataPoints()) {
for(Field field : dp.getDataType().getFields()) {
if (field.getName().equals("steps")) {
String steps = dp.getValue(field).toString();
if (! steps.isEmpty()) {
Log.e("Alarm Receiver History", "\tField: " + field.getName() +
" Value: " + dp.getValue(field));
Log.e ("Alarm", "Steps Count: " + steps);
ServerIntf serverIntf = new ServerIntf();
serverIntf.SendStepCount(mContext, steps);
}
}
}
}
}
private class ViewTodaysStepCountTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
displayStepDataForToday();
return null;
}
protected void onPostExecute(Long result) {
Log.e ("STEPS", "Steps returned");
}
}
public void sendNotification(String text) {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(mContext)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("My notification")
.setContentText("Hello World! " + text );
NotificationManager mNotificationManager =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(002, mBuilder.build());
}
}
Your google api client is most likely null because you are referencing your client as a static variable, but it is most likely null or disconnected by the time the alarm manager starts your service. You need to start your client in the service and use that live client. Here is where you need to look to make the fix:
private GoogleApiClient mGoogleApiClient = MainActivity.mClient;

How to add value on Permission Manager

I was wondering how to set value on manager? Here's how I initialize PermissionManager manager or PermissionManager manager = new?
public PermissionManager manager = new PermissionManager(PermissionManager.mActivity, PermissionManager.mContext);
protected void onStart() {
super.onStart();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
/*String[] list = new String[]{PermissionConsts.PHONE_STATE, PermissionConsts.READ_CONTACTS, PermissionConsts.READ_EXTERNAL_STORAGE,
PermissionConsts.READ_SMS};*/
manager.requestPermission(new String[]{Manifest.permission.ACCESS_FINE_LOCATION});
}
Intent serviceIntent = new Intent(this, LocationFetcherService.class);
startService(serviceIntent);
}
Here it doesn't work:
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera) {
initLocationFetching(this);
}
}
Here is BaseActivityLocation class
public class BaseActivityLocation extends AppCompatActivity implements LocationManagerInterface {
public SmartLocationManager mLocationManager;
public PermissionManager manager = new PermissionManager(BaseActivityLocation.this, BaseActivityLocation.this);
public LocationFetcherService mLocationFetcherService;
private static final int REQUEST_FINE_LOCATION = 1;
private Activity mCurrentActivity;
private int count = 0;
#Override
public void locationFetched(Location mLocation, Location oldLocation, String time, String locationProvider) {
// storing it on application level
GetAccurateLocationApplication.mCurrentLocation = mLocation;
GetAccurateLocationApplication.oldLocation = oldLocation;
GetAccurateLocationApplication.locationProvider = locationProvider;
GetAccurateLocationApplication.locationTime = time;
}
public void instatntiate(Activity mActivity){
/*3rd Parametr*/
//For One time Gps Usage: SmartLocationManager.USE_ONE_TIME_GPS;
//For every 10 seconds Gps Usage: SmartLocationManager.USE_UPDATE_TIME_GPS;
/*4th parameter*/
//For All netwrok Provider: SmartLocationManager.ALL_PROVIDERS;
//For Network Provider only: SmartLocationManager.NETWORK_PROVIDER;
//For GPS Provider only: SmartLocationManager.GPS_PROVIDER;
/*Last Parameter*/
//For using Any Api location: SmartLocationManager.ANY_API; //The priority will be google api.
//For using google Api location: SmartLocationManager.ONLY_GOOGLE_API;
//For using android Api Location: SmartLocationManager.ONLY_ANDROID_API;
mLocationManager = new SmartLocationManager(getApplicationContext(), mActivity, SmartLocationManager.USE_ONE_TIME_GPS, this, SmartLocationManager.ALL_PROVIDERS, LocationRequest.PRIORITY_HIGH_ACCURACY, 10 * 1000, 1 * 1000, SmartLocationManager.LOCATION_PROVIDER_RESTRICTION_NONE, SmartLocationManager.ANY_API); // init location manager
}
public void initLocationFetching(Activity mActivity) {
mCurrentActivity = mActivity;
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
manager = new PermissionManager(mCurrentActivity, getApplicationContext());
PermissionManagerInterface permissionManagerInterface = new PermissionManagerInterface() {
#Override
public void onPermissionGranted(String message, int requestCode) {
}
Here is the code of Permission Manager class but I am having a null value where I want to eliminate
public class PermissionManager implements RequestPermissionsResultInterface {
public static Activity mActivity;
public static Context mContext;
public String[] permissionList;
public boolean flag;
private PermissionManagerInterface mManagerInterface = new PermissionManagerInterface() {
#Override
public void onPermissionGranted(String message, int requestCode) {
}
#Override
public void onPermissionDenied(String message, int requestCode) {
}
#Override
public void isAllGranted(boolean flag) {
}
};
public PermissionManager(Activity mActivity, Context mContext) {
this.mActivity = mActivity;
this.mContext = mContext;
}
public void requestPermission(String[] mList){
permissionList = mList;
ActivityCompat.requestPermissions(mActivity, mList, REQ_CODE);
}
public void getManagerInterface(PermissionManagerInterface mInterface){
mManagerInterface = mInterface;
}
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if(requestCode == REQ_CODE){
for (int i = 0, len = permissions.length; i < len; i++) {
String permission = permissions[i];
String packageStrippedPermissionName = permissions[i].substring(permissions[0].lastIndexOf(".")+1);
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
// user rejected the permission
boolean showRationale = mActivity.shouldShowRequestPermissionRationale( permission );
if (! showRationale) {
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setTitle(permission + " Required");
builder.setMessage("You have to grant this permission , otherwise app will not be able to continue, Click Yes to go to Settings else app will not resume!");
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", mActivity.getPackageName(), null);
intent.setData(uri);
mActivity.startActivityForResult(intent, REQ_CODE);
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(mContext, "App will not Start without this Permission", Toast.LENGTH_SHORT).show();
mActivity.finish();
}
});
builder.setCancelable(false);
builder.show();
// user also CHECKED "never ask again"
// you can either enable some fall back,
// disable features of your app
// or open another dialog explaining
// again the permission and directing to
// the app setting
}else{
mManagerInterface.onPermissionDenied("\'" + packageStrippedPermissionName + "': permission denied", requestCode);
Alert(mActivity, permissions[i]);
}
}else if(grantResults[i] == PackageManager.PERMISSION_GRANTED){
mManagerInterface.onPermissionGranted("\'" + packageStrippedPermissionName + "\': permission granted", requestCode);
}
}
ArrayList<String> list = new ArrayList<>();
for(int k=0; k<grantResults.length; k++){
if(grantResults[k] == PackageManager.PERMISSION_GRANTED){
list.add(permissions[k]);
}
}
if(list.size() == permissions.length){
flag = true;
mManagerInterface.isAllGranted(flag);
}else{
flag = false;
mManagerInterface.isAllGranted(flag);
}
}
}
BaseActivityLocation java class:
BaseActivityLocation extends AppCompatActivity implements LocationManagerInterface {
public SmartLocationManager mLocationManager;
public PermissionManager manager = null;
public LocationFetcherService mLocationFetcherService;
private static final int REQUEST_FINE_LOCATION = 1;
private Activity mCurrentActivity;
private int count = 0;
#Override
public void locationFetched(Location mLocation, Location oldLocation, String time, String locationProvider) {
// storing it on application level
GetAccurateLocationApplication.mCurrentLocation = mLocation;
GetAccurateLocationApplication.oldLocation = oldLocation;
GetAccurateLocationApplication.locationProvider = locationProvider;
GetAccurateLocationApplication.locationTime = time;
}
protected void onStart() {
super.onStart();
manager = new PermissionManager(BaseActivityLocation.this, BaseActivityLocation.this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
/*String[] list = new String[]{PermissionConsts.PHONE_STATE, PermissionConsts.READ_CONTACTS, PermissionConsts.READ_EXTERNAL_STORAGE,
PermissionConsts.READ_SMS};*/
manager.requestPermission(new String[]{Manifest.permission.ACCESS_FINE_LOCATION});
}
Intent serviceIntent = new Intent(this, LocationFetcherService.class);
startService(serviceIntent);
}
protected void onResume(){
super.onResume();
//showLocationPermission();
}
Permission Manager Interface
public interface PermissionManagerInterface extends Serializable
{
String TAG = PermissionManagerInterface.class.getSimpleName();
void onPermissionGranted(String message, int requestCode);
void onPermissionDenied(String message, int requestCode);
void isAllGranted(boolean flag);
}
Try this if this is inside a activity. YourActivity is your activity name:
public PermissionManager manager = null;
protected void onStart() {
super.onStart();
manager = new PermissionManager(YourActivity.this, YourActivity.this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
/*String[] list = new String[]{PermissionConsts.PHONE_STATE, PermissionConsts.READ_CONTACTS, PermissionConsts.READ_EXTERNAL_STORAGE,
PermissionConsts.READ_SMS};*/
manager.requestPermission(new String[]{Manifest.permission.ACCESS_FINE_LOCATION});
}
Intent serviceIntent = new Intent(this, LocationFetcherService.class);
startService(serviceIntent);
}

My Android ActivityRecognition implementation is too slow

I used Google ActivityRecognitionApi for tracking whether i am walking or not.
But It seems too slow. What's the problem?
It doesn't related to internet connectivity.
[Walking.java]
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_walking);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(ActivityRecognition.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle bundle) {
Intent intent = new Intent(this, ActivityRecognitionService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(mGoogleApiClient, 1000, pendingIntent);
}
#Override
public void onConnectionSuspended(int i) {
Toast.makeText(Walking.this, "Hello1", Toast.LENGTH_SHORT).show();
Log.e("Connection Failed : ", "Connection Failed");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Toast.makeText(Walking.this, "Hello2", Toast.LENGTH_SHORT).show();
Log.e("Connection Failed : ", "Connection Failed");
}
[ActivityRecognitionService.java]
import java.util.List;
public class ActivityRecognitionService extends IntentService {
public static final String ACTION_IntentService = "com.example.android.skywalker.RESPONSE";
public static final String ACTIVITY_RESULT = "RESULT";
public Intent localIntent;
public ActivityRecognitionService() {
super("ActivityRecognitionService");
}
public ActivityRecognitionService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
if(ActivityRecognitionResult.hasResult(intent)) {
ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
handleDetectedActivities(result.getProbableActivities());
}
}
private void handleDetectedActivities(List<DetectedActivity> probableActivities) {
int Flag = 0;
for(DetectedActivity activity : probableActivities) {
if(activity.getType() == DetectedActivity.ON_FOOT) {
Flag = 1;
if (activity.getConfidence() >= 50) Log.e("YES", "YES");
break;
}
}
//Intent intent = new Intent(ActivityRecognitionService.this, Walking.class);
if (Flag == 0) {
//localIntent = new Intent(Walking.BROADCAST_ACTION).putExtra(Walking.RESPONSE_STATUS, "YES");
Log.e("NO", "NO");
}
}
}
I don't think there is any problem with your code, it looks exactly the same as mine.
The normal rate for detection is 3 seconds -> 6 seconds if your "detectionIntervalMillis" value = 0.
But when you switch between 2 different activities (for example: from walking -> in the car....) it will take more, maybe 20s to 40s.

Resume ProgressBar in Activity from current running Service

I created an Android app that can downloading file.
I used Groundy library to support the service. And I created the NotiThread from this (but I edited it for support my requirement)..
Here is my Activity code ...
public class PacksActivity extends Activity {
private Context context;
private RelativeLayout download;
private ProgressBar progressBar;
private NotiThread notification;
private String url;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.packs);
context = this;
url = getIntent().getStringExtra("URL");
progressBar = (ProgressBar)findViewById(R.id.progress);
progressBar.setIndeterminate(false);
progressBar.setMax(100);
download = (RelativeLayout) findViewById(R.id.label_circle);
download.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
File dest = new File(context.getFilesDir(), new File(url).getName());
if(!dest.exists()){
progressBar.setVisibility(View.VISIBLE);
notification = new NotiThread(context);
notification.run();
Bundle extras = new Bundler().add(DownloadTemplate.PARAM_URL, url).build();
Groundy.create(context, DownloadTemplate.class)
.receiver(mReceiver)
.params(extras)
.queue();
}
}
});
}
private ResultReceiver mReceiver = new ResultReceiver(new Handler()) {
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
switch (resultCode) {
case Groundy.STATUS_PROGRESS:
int progress = resultData.getInt(Groundy.KEY_PROGRESS);
progressBar.setProgress(progress);
if((progress % 10) == 0)notification.progressUpdate(progress);
break;
case Groundy.STATUS_FINISHED:
Toast.makeText(context, "Success Download file", Toast.LENGTH_LONG);
progressBar.setVisibility(View.GONE);
notification.completed();
break;
case Groundy.STATUS_ERROR:
Toast.makeText(context, resultData.getString(Groundy.KEY_ERROR), Toast.LENGTH_LONG).show();
progressBar.setVisibility(View.GONE);
notification.completed();
break;
}
}
};
}
This is my NotiThread class
public class NotiThread extends Thread {
private NotificationManager mNoti = null;
private final Context mContext;
private final int mUnique;
private Notification noti;
public NotiThread(Context context) {
super("NotiThread");
mContext = context;
mNoti = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mUnique = 1;
}
#Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
noti = new Notification(R.drawable.icon1024, "title", System.currentTimeMillis());
noti.flags |= Notification.FLAG_ONGOING_EVENT;
RemoteViews contentView = new RemoteViews(mContext.getPackageName(), R.layout.custom_notification);
contentView.setTextViewText(R.id.noti_title, "title");
contentView.setProgressBar(R.id.noti_progress, 100, 0, false);
contentView.setTextViewText(R.id.noti_text, "0%");
noti.contentView = contentView;
noti.contentIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, mContext.getClass()), PendingIntent.FLAG_ONE_SHOT);
mNoti.notify(mUnique, noti);
}
public void progressUpdate(int percentageComplete) {
noti.contentView.setProgressBar(R.id.noti_progress, 100, percentageComplete, false);
noti.contentView.setTextViewText(R.id.noti_text, percentageComplete + "%");
mNoti.notify(mUnique, noti);
}
public void completed() {
mNoti.cancel(mUnique);
}
}
And this is GroundyTask class
public class DownloadTemplate extends GroundyTask {
public static final String PARAM_URL = "com.app.service.PARAM_URL";
#Override
protected boolean doInBackground() {
try {
String url = getParameters().getString(PARAM_URL);
File dest = new File(getContext().getFilesDir(), new File(url).getName());
DownloadUtils.downloadFile(getContext(), url, dest, DownloadUtils.getDownloadListenerForTask(this));
return true;
} catch (Exception e) {
return false;
}
}
}
I want to ask, how to resume activity to update the ProgressBar from the current running service when enter to the activity and from notification?
You can check if the service is still running when coming back to your activity. How I do it is I use a singleton Network class. Here I define the callback object that is used in the Groundy create function. This singleton also keeps track of the state of the task (running, or not running when cancelled, finished or failed). When the activity is created again, this singleton class still exists so the progress callback is still being fired. The only thing you need to make sure is to re-register your listeners from the new activity to the existing singleton. Here's a simple example..
Singleton class:
public static SingletonClass getInstance(Object o) {
if (instance == null) {
instance = new SingletonClass();
}
if (o instanceof OnProgressListener) {
progressListener = (OnProgressListener) o;
}
...
return instance;
}
Callback object:
public Object callbackObject = new Object() {
#OnProgress(YourGroundyTask.class)
public void onProgress(#Param(Groundy.PROGRESS) int progress) {
if (progressListener != null){
progressListener.onDownloadProgress(progress);
}
}
...

Categories

Resources