Here I am creating a chat app. In this app I want to load data from firebase realtime database whenever user switch on his internet or connects his phone to wifi no matter whether the app is open or not. I am doing this using service and broadcast. But I don't know why its not working. The method of fetching data is working properly as I have checked it in another activity. Kindly checkout my codes below
I have registered my broadcast and service in menifest file as
<service android:name=".broadcasts.receiveMsgService" android:exported="true"/>
<receiver android:name=".broadcasts.receiveChattersBroadcast"
android:exported="true"
android:enabled="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
My broadcast file
public class receiveChattersBroadcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Check the action of the intent
String action = intent.getAction();
if (action.equals(Intent.ACTION_BOOT_COMPLETED) ||
action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
// Start the background service
Intent serviceIntent = new Intent(context, receiveMsgService.class);
context.startService(serviceIntent);
}
}
}
My service file
public class receiveMsgService extends Service {
private static final String LOG_TAG = "MyForegroundService";
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(LOG_TAG, "onStartCommand");
// Load the messages from Firebase
loadMessagesFromFirebase();
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
public void loadMessagesFromFirebase(){
FirebaseDatabase database;
DatabaseReference refernec;
// chatrecycler = view.findViewById(R.id.fragAllChatRecycler);
database = FirebaseDatabase.getInstance();
refernec = FirebaseDatabase.getInstance().getReference();
refernec.keepSynced(true);
ArrayList<chatterModal2> modals = new ArrayList();
SharedPreferencelogin session = new SharedPreferencelogin(getApplicationContext());
String userFireId = session.getFireId();
databaseHelper db = new databaseHelper(getApplicationContext());
database.getReference().child("chatters").addValueEventListener(new
ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists()){
for (DataSnapshot snapshot1:snapshot.getChildren()){
chatterModal2 modal = snapshot1.getValue(chatterModal2.class) ;
String receiverId = modal.getRecieverId();
String sender = modal.getSenderId();
if(receiverId.trim().equals(userFireId) ||
sender.equals(userFireId)) {
modals.add(modal);
String addResult = db.addChatter(modal.getRecieverId(),
modal.getSenderId(), modal.getMsg(), modal.getUnseen(), modal.getProId(),
String.valueOf(modal.getTime()));
}else{
//do nothing
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
}
I have not mentioned this service and broadcast any where else. Do I have to mention it or call it in any activity? Please tell me what's wrong
Related
I have implemented a foreground service with a notification for my existing android project.
Problem: I remove the app from the "recent app" when the foreground service is running and its notification is visible. Later, I try to launch the app by clicking on the app icon. A black screen appears for a second and the app is not launched.
The app is stuck in this state until I got to app settings and force close the application.
Foreground Service:
public class FileSyncService extends Service {
private static final int FILE_SYNC_SERVICE_ID = 901;
public static final String FILE_SYNC_SERVICE_ACTION_STOP = "StopFileSyncService";
public static final String FILE_SYNC_SERVICE_ACTION_START = "StartFileSyncService";
#Inject
private FilePushManager filePushManager;
#Inject
private NotificationController notificationController;
#Override
public void onCreate() {
super.onCreate();
Logger.d("[FileSyncService][onCreate]");
BootstrappingManager.getInstance().getInjector().injectMembers(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Logger.d("[FileSyncService][onStartCommand]");
if (intent != null && intent.getAction() != null && intent.getAction().equals(FILE_SYNC_SERVICE_ACTION_STOP)) {
Logger.d("[FileSyncService][onStartCommand] stopSelf");
stopForegroundService();
} else {
Logger.d("[FileSyncService][onStartCommand] startForeground");
startForeground(FILE_SYNC_SERVICE_ID, notificationController.createFileSyncNotification());
filePushManager.startFilePush();
}
return START_STICKY;
}
#Override
public void onDestroy() {
Logger.d("[FileSyncService] onDestroy");
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void stopForegroundService() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
stopForeground(STOP_FOREGROUND_REMOVE);
} else {
stopForeground(true);
}
stopSelf();
}
}
Methods to start stop service:
public static void startFileSyncService(Context context) {
Intent serviceIntent = new Intent(context, FileSyncService.class);
serviceIntent.setAction(FileSyncService.FILE_SYNC_SERVICE_ACTION_START);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Logger.d("[MandatoryUtils][startFileSyncService] foreground");
try {
context.startForegroundService(serviceIntent);
} catch (SecurityException e) {
Logger.e("[MandatoryUtils][startFileSyncService] unable to start File Sync Service", e);
} catch (Exception e) {
Logger.e("[MandatoryUtils][startFileSyncService] unable to start File Sync Service Exception", e);
}
} else {
Logger.d("[MandatoryUtils][startFileSyncService] ");
context.startService(serviceIntent);
}
}
public static void stopFileSyncService(Context context) {
Logger.d("[MandatoryUtils][stopFileSyncService]");
Intent serviceIntent = new Intent(context, FileSyncService.class);
serviceIntent.setAction(FileSyncService.FILE_SYNC_SERVICE_ACTION_STOP);
context.startService(serviceIntent);
}
Launcher Activity:
<application
android:name="net.activities.MainApplication"
android:allowBackup="false"
android:icon="#drawable/scl"
android:label="#string/app_name"
android:manageSpaceActivity="net.activities.SplashActivity"
android:networkSecurityConfig="#xml/network_security_config"
android:resizeableActivity="false"
android:theme="#style/ContentLibraryTheme"
tools:replace="allowBackup, android:theme">
<uses-library android:name="org.apache.http.legacy" android:required="false" />
<activity
android:name="net.activities.SplashActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:theme="#style/Theme.App.Splash"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
...
I have an Android app that specifies two AIDL files and a service. This service should be used from another app to invoke the methods defined on the AIDL. I have followed the Android Documentation on AIDL to implement the AIDL files and the service (see the code below).
Then I created a very simple client app (also shown below) to bind to the service and invoke the method defined on my AIDL file. However, the bindService always returns false and mentions that the intent cannot be found. These are some things I tried to correctly reference the intent on the client side:
Intent intent = new Intent("a.b.c.service");
intent.setPackage("a.b.c");
---
Intent intent = new Intent("service");
intent.setPackage("a.b.c");
---
Intent intent = new Intent();
intent.setClassName("a.b.c", "a.b.c.services.MyService");
---
Intent intent = new Intent();
intent.setClassName("a.b.c.services", "a.b.c.services.MyService");
---
Intent intent = new Intent();
intent.setClassName("a.b.c", ".services.MyService");
---
Intent intent = new Intent();
intent.setAction("service");
intent.setPackage("a.b.c");
intent.setClassName("a.b.c", ".services.MyService");
---
Intent intent = new Intent();
intent.setAction("service");
intent.setClassName("a.b.c", ".services.MyService");
If I try from the same application where the service resides, I can use the following and it will work:
Intent intent = new Intent(this, MyService.class);
But since this is a remote service, I do not have access to MyService class from the client app, so I can't find any way of making it work.
I have wondered through a lot of StackOverflow posts without any luck. Examples:
Android: Binding to a remote service
How can I use AIDL remote service to deal with defferent clients' concurrent requests?
Android Bind Service returns false every time
How should I specify my intent in this case?
Thanks in advance.
Relevant code:
IServiceInterface.aidl
package a.b.c;
import a.b.c.IServiceInterfaceGetStuffCallback;
interface IServiceInterface
{
void getStuff(String arg1, IServiceInterfaceGetStuffCallback callback);
}
IServiceInterfaceGetStuffCallback
package a.b.c;
interface IServiceInterfaceGetStuffCallback
{
void onGetStuffResponse(String arg1, boolean arg2, int arg3, int arg4);
}
a.b.c./services/MyService.java
public class MyService extends Service
{
private final MyService self = this;
private MyServiceHandler handler = null;
private final HandlerThread handlerThread = new HandlerThread("AidlServiceThread");
//Callbacks
private final ArrayList<IServiceInterfaceGetStuffCallback> getStuffCallbacks = new ArrayList<>();
private final int MY_SERVICE_GET_STUFF_MSG = 1;
public MyService()
{
}
#Override
public IBinder onBind(Intent intent)
{
// Handler Thread handling all callback methods
handlerThread.start();
handler = new MyServiceHandler(handlerThread.getLooper());
return mBinder;
}
IServiceInterface.Stub mBinder = new IServiceInterface.Stub()
{
#Override
public void getStuff(String arg1, IServiceInterfaceGetStuffCallback callback) throws RemoteException
{
//Register the callback internally
getStuffCallbacks.add(callback);
final int cbIndex = getStuffCallbacks.size() - 1;
getStuff((arg1, arg2, arg3, arg4) ->
{
MyServiceResponse response = new MyServiceResponse();
response.arg1 = arg1;
response.arg2 = arg2;
response.arg3 = arg3;
response.arg4 = arg4;
Message message = handler.obtainMessage();
message.arg1 = cbIndex;
message.obj = response;
message.what = MY_SERVICE_GET_STUFF_MSG;
handler.sendMessage(message);
});
}
};
private class MyServiceHandler extends Handler
{
int callbackIndex = 0;
MyServiceHandler (Looper looper)
{
super(looper);
}
#Override
public void handleMessage(Message msg)
{
callbackIndex = msg.arg1;
MyServiceHandler response = (MyServiceHandler)msg.obj;
switch (msg.what)
{
case MY_SERVICE_GET_STUFF_MSG:
{
try
{
getStuffCallbacks.get(callbackIndex).onGetStuffResponse(response.arg1, response.arg2, response.arg3, response.arg4);
}
catch (RemoteException e)
{
e.printStackTrace();
}
break;
}
default:
break;
}
}
}
private static class MyServiceResponse
{
public String arg1;
public boolean arg2;
public int arg3;
public int arg4;
}
}
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="a.b.c">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<permission
android:name="a.b.c.myservice"
android:protectionLevel="signature" />
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|keyboard|colorMode|density|navigation|fontScale|layoutDirection|locale|mcc|mnc|smallestScreenSize|touchscreen|uiMode">
(...)
<service
android:name="a.b.c.services.MyService"
android:enabled="true"
android:exported="true"
android:permission="a.b.c.myservice">
<intent-filter>
<action android:name="a.b.c.myservice" />
</intent-filter>
</service>
</application>
</manifest>
Client app - MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener
{
private final String TAG = "aidltest";
MainActivity self = this;
IServiceInterface service = null;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_get_stuff).setOnClickListener(this);
}
#Override
public void onClick(View view)
{
if (view.getId() == R.id.btn_get_stuff)
getStuff();
}
void getStuff()
{
Log.e(TAG, "getStuff invoked");
Intent intent = new Intent("a.b.c.myservice");
intent.setPackage("a.b.c");
boolean res = getApplicationContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
Log.e(TAG, "Service binding result: " + res);
}
private ServiceConnection serviceConnection = new ServiceConnection()
{
public void onServiceConnected(ComponentName className, IBinder service)
{
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. We are communicating with our
// service through an IDL interface, so get a client-side
// representation of that from the raw service object.
self.service = IServiceInterface.Stub.asInterface(service);
Log.e(TAG, "ServiceInterface attached");
}
public void onServiceDisconnected(ComponentName className)
{
service = null;
Log.e(TAG, "Service disconnected");
}
};
}
The following changes work for me:
Adjust your manifest as follows:
<service
android:name="a.b.c.services.MyService"
android:enabled="true"
android:exported="true"
android:permission="a.b.c.myservice">
<intent-filter>
<action android:name="a.b.c.myservice" />
<category android:name="android.intent.category.DEFAULT"/> <---- NEW LINE
</intent-filter>
</service>
Run adb shell pm list packages and get the package id of the apk where you declared the service. This is needed for building the intent in step 3. Let's call it PACKAGE_ID.
Adjust the getStuff method as follows:
void getStuff() {
Log.e(TAG, "getStuff invoked");
Intent intent = new Intent("a.b.c.myservice"); // This is the value you used in the action for your service as declared in the manifest.
intent.setPackage(PACKAGE_ID); // This is the value you retrieved in step 2.
boolean res = getApplicationContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
Log.e(TAG, "Service binding result: " + res);
}
There are answered questions regarding FileObserver in Android and I am following them but still my code doesn't work. Here I am posting my code, I am trying to set fileObserver via service so it work even if the app itself is closed. When running, it is invoking the DirectoryObserver Constructor but adding or deleting a file doesn't invoke the event
public class MainActivity extends AppCompatActivity
{
private String sharedPreferencesKey = "IsThisFIrstTime";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
if (!preferences.contains(sharedPreferencesKey)) {
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean(sharedPreferencesKey, false);
editor.apply();
try {
startTheServices();
}
catch (Exception ex) {
}
}
setContentView(R.layout.activity_main);
}
private void startTheServices()
{
Intent intent = new Intent(this, BackgroundServices.class);
startService(intent);
}
}
public class BackgroundServices extends Service {
#Override
public void onCreate(){
super.onCreate();
Toast.makeText(this, "This is on Create", Toast.LENGTH_LONG).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "This is on onStartCommand", Toast.LENGTH_LONG).show();
Thread thread = new Thread(new ThreadClass(startId));
thread.start();
return super.onStartCommand(intent, flags, startId);
//return START_STICKY;
}
#Override
public void onDestroy(){
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
final class ThreadClass implements Runnable {
int _serviceId;
ThreadClass(int serviceId) {
_serviceId = serviceId;
}
#Override
public void run() {
DirectoryObserver directoryObserver = new DirectoryObserver(new File(Environment.getExternalStorageDirectory(), Constants.Camera_Directory).getAbsolutePath(), getApplicationContext());
directoryObserver.startWatching();
}
}
}
public class DirectoryObserver extends FileObserver {
private static final String TAG = "DIRECTORY_OBERSVER";
private String directoryPath;
private Context _context;
public DirectoryObserver(String path, Context context) {
super(path);
Log.i(TAG, "Something Happening " + path);
_context = context;
directoryPath = path;
}
#Override
public void onEvent(int event, #Nullable String path) {
if (path == null) {
return;
}
//a new file or subdirectory was created under the monitored directory
if ((FileObserver.CREATE & event)!=0) {
Log.i(TAG, "A file is added to the path " + path);
Toast.makeText(_context, "A new file has been added", Toast.LENGTH_LONG).show();
}
if ((FileObserver.DELETE & event)!=0) {
Log.i(TAG, "A file is deleted to the path " + path);
//Context.getApplicationContext();
}
}
}
And following is the menifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="someone.package">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<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=".BackgroundServices" android:exported="false"></service>
</application>
</manifest>
Have You Added The Permission? I Don't Have Enough Reps Otherwise I Would have Commented.
The problem here is that the FileObserver is probably being garbage collected, as you can see here:
Warning: If a FileObserver is garbage collected, it will stop sending events. To ensure you keep receiving events, you must keep a reference to the FileObserver instance from some other live object.
Android might be getting rid of your service, or even the FileObserver itself. Try to see if the code is entering the "startWatching()" method, or even if the service is starting.
The solution I found is that move the following initialization of DirectoryObserver
DirectoryObserver directoryObserver = new DirectoryObserver(new File(Environment.getExternalStorageDirectory(), Constants.Camera_Directory).getAbsolutePath(), getApplicationContext());
to
public int onStartCommand(Intent intent, int flags, int startId)
method in BackgroundService Class before following lines
Thread thread = new Thread(new ThreadClass(startId));
thread.start();
I have an app in which user input his details in edit text and send Register request to server and after server success response a dialog will open and need confirmation by user here I want to check whether device is in airplane mode or not if yes then move Dismiss dialog otherwise send user details to server.
code:-
private final BroadcastReceiver m_oAIRPLANE_MODE_CHECKER = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
otpRequest();
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate..............");
setContentView(R.layout.registration_screen);
defaultConfigration();// defining default configuration
init();// Initialize controls
/*Registered Broadcast receiver*/
IntentFilter m_intentFilter = new IntentFilter();// creating object of Intentfilter class user for defining permission
m_intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");// action to check Internet connection
getApplicationContext().registerReceiver(m_oInternetChecker, m_intentFilter);// register receiver....
m_oAirplaneModeIntent = new IntentFilter();
m_intentFilter.addAction("android.intent.action.AIRPLANE_MODE");
getApplicationContext().registerReceiver(m_oAIRPLANE_MODE_CHECKER,m_oAirplaneModeIntent);
}
/*Unregistered broadcast receiver*/
#Override
public void onDestroy() {// unregister broadcast receiver ........
super.onDestroy();
Log.i(TAG, "onDestroy.............");
getApplicationContext().unregisterReceiver(m_oInternetChecker);// unregistaer broadcast receiver.
getApplicationContext().unregisterReceiver(m_oAIRPLANE_MODE_CHECKER);
}
here I want to make a check
String sourceString = "We will send you a verification SMS to this Number.<br/><br/> <b><font color='#2196F3'>" + s_szResponseMobileNum + "</b> <br/><br/>Please ensure that this number is active on this device.";
m_OTPAlertBuilder = new AlertDialog.Builder(CRegistrationScreen.this, R.style.AppCompatAlertDialogStyle);
m_OTPAlertBuilder.setCancelable(false);
m_OTPAlertBuilder.setMessage(Html.fromHtml(sourceString));
m_OTPAlertBuilder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
/*This method send request to server to generate OTP*/
/* condition to check whether app is in background*/
if (NetworkUtil.isAppIsInBackground(getApplicationContext())) {
/*if app is in background then start service*/
Intent i = new Intent(CRegistrationScreen.this, OtpGenrateService.class);
getApplicationContext().startService(i);
} else {
/*if app is in forground the send data to server*/
/*this method genrate otp */
generateOtp();
}
}
});
You can check if device is in airplane mode using this snippet:
public static boolean isInAirplaneModeOn(Context context){
return Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0;
}
Also, you can set up broadcast receiver to receive ACTION_AIRPLANE_MODE_CHANGED broadcast. Programatically:
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do your stuff here
boolean inAirplaneMode = AirplaneModeHelper.isInAirplaneMode(context);
Log.i("AIRPLANE", "In airplane mode: " + inAirplaneMode);
}
};
context.registerReceiver(receiver, new IntentFilter("android.intent.action.ACTION_AIRPLANE_MODE_CHANGED"));
Or using manifest:
<receiver android:enabled="true" android:name=".YourReceiver">
<intent-filter>
<action android:name="android.intent.action.ACTION_AIRPLANE_MODE_CHANGED"/>
</intent-filter>
</receiver>
I am trying to use the AWS Android SDK for S3 in a started service. I am a little new to both the SDK and Services. I am pretty confident that the Transfer Utility is also running a service.
Handler (android.os.Handler) {11629d87} sending message to a Handler on a dead thread
java.lang.IllegalStateException: Handler (android.os.Handler) {11629d87} sending message to a Handler on a dead thread
at android.os.MessageQueue.enqueueMessage(MessageQueue.java:325)
at android.os.Handler.enqueueMessage(Handler.java:631)
at android.os.Handler.sendMessageAtTime(Handler.java:600)
at android.os.Handler.sendMessageDelayed(Handler.java:570)
at sksDoneLater(TransferService.java:189)
at com.amazonaws.mobileconnectors.s3.transferutility.TransferService.access$200(TransferService.java:44)
at com.amazonaws.mobileconnectors.s3.transferutility.TransferService$2.handleMessage(TransferService.java:166)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:135)
at android.os.HandlerThread.run(HandlerThread.java:61)
Here is the code I am using to start it up:
AmazonS3 amazonS3 = new AmazonS3Client(credentialsProvider);
mTransferUtility = new TransferUtility(amazonS3, getApplicationContext());
TransferObserver observer = mTransferUtility.upload(
S3_RAW_BUCKET_ARN,
mVidFileKey,
mVidFile);
observer.setTransferListener(new TransferListener() {...})
The line previous it says it can't get s3 client. I created the client just as shown above in application class and successfully used the same code in an activity to perform a successful transfer so it must be something obvious about services that I am ignorant of. The above code is called in a method that is called from onStartCommand() in the service.
Any help would be much appreciated.
UPDATE - Whole Class was requested and is shown here:
public class VideoCompressionService extends Service {;
private Bus bus;
private TransferUtility mTransferUtility;
private int mVidWidth;
private int mVidHeight;
private File mCompressedVidFile;
private File mVidFile;
private String mVidFileKey;
private NotificationManager mNotificationManager;
private android.support.v4.app.NotificationCompat.Builder mNotification;
public VideoCompressionService() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
String realPath = MediaUtils.getRealVideoPathFromURI(this.getContentResolver(), intent.getData());
if (realPath != null) {
this.mVidFile = new File(realPath);
this.mVidFileKey = intent.getStringExtra(EXTRA_VID_FILE_KEY);
this.mVidWidth = intent.getIntExtra(EXTRA_VID_WIDTH, 0);
this.mVidHeight = intent.getIntExtra(EXTRA_VID_HEIGHT, 0);
this.bus = CoPhotoApplication.getVideoCompressionBus();
if (mVidFile != null && mVidFile.exists() && mVidFile.canRead()) {
mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
mNotification = new NotificationCompat.Builder(this)
.setContentTitle("Compressing Video - Step 1 of 3")
.setContentText("Uploading video for processing...")
.setSmallIcon(R.drawable.ic_launcher);
if (mVidWidth == 0 || mVidHeight == 0) {
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(mVidFile.getAbsolutePath());
mVidWidth = Integer.parseInt(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
mVidHeight = Integer.parseInt(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
mmr.release();
}
uploadVidToS3();
}
return Service.START_NOT_STICKY;
} else {
VideoCompressionService.this.stopSelf();
return Service.START_NOT_STICKY;
}
} else {
VideoCompressionService.this.stopSelf();
return Service.START_NOT_STICKY;
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void uploadVidToS3() {
compressionUploadStarted();
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(),
"*********ID HERE********", // Identity Pool ID
Regions.US_EAST_1 // Region
);
AmazonS3 amazonS3 = new AmazonS3Client(credentialsProvider);
mTransferUtility = new TransferUtility(amazonS3, getApplicationContext());
TransferObserver observer = mTransferUtility.upload(
S3_RAW_BUCKET_ARN,
mVidFileKey,
mVidFile);
observer.setTransferListener(new TransferListener() {
#Override
public void onStateChanged(int id, TransferState state) {
if (state == TransferState.COMPLETED) {
compressionUploadFinished(true);
zencodeVideo(mVidFileKey);
} else if (state == TransferState.FAILED) {
compressionUploadFinished(false);
}
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
int progress = Math.round(100 * ((float) bytesCurrent / bytesTotal));
String progressPercentage = String.valueOf(progress) + "%";
compressionUploadProgress(progress, progressPercentage);
}
#Override
public void onError(int id, Exception ex) {
compressionUploadFinished(false);
}
});
}
private void compressionUploadStarted() {
bus.post(new CompressionUploadStartedEvent());
updateNotification();
}
private void compressionUploadProgress(int progress, String progressPercentage) {
bus.post(new CompressionUploadProgressEvent(progress, progressPercentage));
mNotification.setProgress(100, progress, false);
updateNotification();
}
private void compressionUploadFinished(boolean successfully) {
bus.post(new CompressionUploadFinishedEvent(successfully));
if (successfully) {
mNotification.setContentText("Upload complete");
} else {
mNotification.setContentTitle("Compression Failed");
mNotification.setContentText("Upload failed. Please try again later.");
}
updateNotification();
if (!successfully) {
VideoCompressionService.this.stopSelf();
}
}
private void updateNotification() {
mNotificationManager.notify(NOTIFICATION_ID, mNotification.build());
}
I found myself in the same issue...
Here it is what solved for me:
I noticed I had the following service for my SyncAdapter registered in Manifest:
<service
android:name=".sync.SyncService"
android:exported="true"
android:process=":sync">
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="#xml/syncadapter" />
</service>
The android:process=":sync" tells service to run in a private process called :sync
So I just told the TransferService from Amazon SDK to run in this same thread.
<service
android:name="com.amazonaws.mobileconnectors.s3.transferutility.TransferService"
android:process=":sync"
android:enabled="true" />
After that, I no more got the error TransferService can't get s3 client, and it will stop, and finally was able to upload my pictures to S3
You should declare the client as a global variable, as the garbage collector could delete it if you don't do it.