I want to run a Backgroundservice (FileObserver) that will look for any filechanges in the system (CREATE, DELETE, MOVE, ...).
When I start my application it works a few seconds and logs everything fine. For example at taking a picture by the camera it logs that. After a few seconds the service is still listed in Settings => Developer Options => Running Services but does not work and log anything anymore.
Android Version: 7.0
Device: Samsung Galaxy S7 Edge
I copied the code from Niza Siwale's answer here 1:1 and added only the Logs like that :
How to monitor folder for file changes in background?
#Override
public void onEvent(int event, final String path) {
if (event == FileObserver.OPEN) {
Log.v("Event: ", "Open" + path);
} else if (event == FileObserver.CREATE && (!path.equals(".probe"))) {
Log.v("Event: ", "Create" + path);
} else if (event == FileObserver.DELETE_SELF || event == FileObserver.DELETE) {
Log.v("Event: ", "Delete" + path);
} else if (event == FileObserver.MOVE_SELF || event == FileObserver.MOVED_FROM || event == FileObserver.MOVED_TO) {
Log.v("Event: ", "Move" + path);
}
}
Why is the service running in background (as I can see in Running Services) but not donig any logs, if something changes in the filesystem?
Full Code:
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.spicysoftware.phonesaver">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- Adding the permission -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<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">
<service
android:name=".FileSystemObserverService"
android:enabled="true"
android:exported="true" >
</service>
<!-- Declaring broadcast receiver for BOOT_COMPLETED event. -->
<receiver android:name=".StartupReceiver" android:enabled="true" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity
package com.spicysoftware.phonesaver;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.FileObserver;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
String TAG = "Log: ";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(isReadStoragePermissionGranted()){
Intent myIntent = new Intent(this, FileSystemObserverService.class);
this.startService(myIntent);
}
}
public boolean isReadStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= 23) {
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
Log.v(TAG,"Permission is granted1");
return true;
} else {
Log.v(TAG,"Permission is revoked1");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 3);
return false;
}
}
else { //permission is automatically granted on sdk<23 upon installation
Log.v(TAG,"Permission is granted1");
return true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 3:
Log.d(TAG, "External storage1");
if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
}else{
}
break;
}
}
}
FileSystemOberveService
package com.spicysoftware.phonesaver;
import android.app.Service;
import android.content.Intent;
import android.os.Environment;
import android.os.FileObserver;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class FileSystemObserverService extends Service {
String externalPath = "";
String internalPath = "";
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
observe();
return super.onStartCommand(intent, flags, startId);
}
public File getInternalStoragePath() {
File parent = Environment.getExternalStorageDirectory().getParentFile();
File external = Environment.getExternalStorageDirectory();
File[] files = parent.listFiles();
File internal = null;
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (files[i].getName().toLowerCase().startsWith("sdcard") && !files[i].equals(external)) {
internal = files[i];
}
}
}
return internal;
}
public File getExtenerStoragePath() {
return Environment.getExternalStorageDirectory();
}
public void observe() {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
//File[] listOfFiles = new File(path).listFiles();
File str = getInternalStoragePath();
if (str != null) {
internalPath = str.getAbsolutePath();
new Obsever(internalPath).startWatching();
}
str = getExtenerStoragePath();
if (str != null) {
externalPath = str.getAbsolutePath();
new Obsever(externalPath).startWatching();
}
}
});
t.setPriority(Thread.MIN_PRIORITY);
t.start();
}
class Obsever extends FileObserver {
List<SingleFileObserver> mObservers;
String mPath;
int mMask;
public Obsever(String path) {
// TODO Auto-generated constructor stub
this(path, ALL_EVENTS);
}
public Obsever(String path, int mask) {
super(path, mask);
mPath = path;
mMask = mask;
// TODO Auto-generated constructor stub
}
#Override
public void startWatching() {
// TODO Auto-generated method stub
if (mObservers != null)
return;
mObservers = new ArrayList<SingleFileObserver>();
Stack<String> stack = new Stack<String>();
stack.push(mPath);
while (!stack.empty()) {
String parent = stack.pop();
mObservers.add(new SingleFileObserver(parent, mMask));
File path = new File(parent);
File[] files = path.listFiles();
if (files == null) continue;
for (int i = 0; i < files.length; ++i) {
if (files[i].isDirectory() && !files[i].getName().equals(".") && !files[i].getName().equals("..")) {
stack.push(files[i].getPath());
}
}
}
for (int i = 0; i < mObservers.size(); i++) {
mObservers.get(i).startWatching();
}
}
#Override
public void stopWatching() {
// TODO Auto-generated method stub
if (mObservers == null)
return;
for (int i = 0; i < mObservers.size(); ++i) {
mObservers.get(i).stopWatching();
}
mObservers.clear();
mObservers = null;
}
#Override
public void onEvent(int event, final String path) {
if (event == FileObserver.OPEN) {
Log.v("Event: ", "Open" + path);
// makeToast("Opened: "+path);
} else if (event == FileObserver.CREATE && (!path.equals(".probe"))) {
Log.v("Event: ", "Create" + path);
// makeToast("Created: "+path);
} else if (event == FileObserver.DELETE_SELF || event == FileObserver.DELETE) {
Log.v("Event: ", "Delete" + path);
// makeToast("Deleted: "+path);
} else if (event == FileObserver.MOVE_SELF || event == FileObserver.MOVED_FROM || event == FileObserver.MOVED_TO) {
Log.v("Event: ", "Move" + path);
// makeToast("Moved: "+path);
}
}
private class SingleFileObserver extends FileObserver {
private String mPath;
public SingleFileObserver(String path, int mask) {
super(path, mask);
// TODO Auto-generated constructor stub
mPath = path;
}
#Override
public void onEvent(int event, String path) {
// TODO Auto-generated method stub
String newPath = mPath + "/" + path;
Obsever.this.onEvent(event, newPath);
}
}
}
/*
public void makeToast(final String strMessage){
//Let this be the code in your n'th level thread from main UI thread
Handler h = new Handler(Looper.getMainLooper());
h.post(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), strMessage, Toast.LENGTH_SHORT).show();
}
});
}
*/
}
StartupReceiver
package com.spicysoftware.phonesaver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class StartupReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent myIntent = new Intent(context, FileSystemObserverService.class);
context.startService(myIntent);
}
}
Related
I added achievements to my Google Play game following Google's tutorial. They unlock fine and if I display achievements in-game immediately they show up. If I quit the game and go to the Google Game's app they don't show up and they disappear from in-game also. Any ideas? I've tried multiple accounts. Thanks!
package com.b1stable.tth;
import java.io.File;
import java.io.FileFilter;
import java.util.Locale;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.FileSystems;
import java.util.Vector;
import android.os.Bundle;
import android.os.Build;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.net.Uri;
import android.os.Vibrator;
import android.os.VibrationEffect;
import android.util.Log;
import android.view.Surface;
import android.view.Gravity;
import org.libsdl.app.SDLActivity;
import com.b1stable.tth.License_Viewer_Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInClient;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.auth.api.signin.GoogleSignInResult;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.games.AchievementsClient;
import com.google.android.gms.games.AnnotatedData;
import com.google.android.gms.games.EventsClient;
import com.google.android.gms.games.Games;
import com.google.android.gms.games.GamesClient;
import com.google.android.gms.games.LeaderboardsClient;
import com.google.android.gms.games.Player;
import com.google.android.gms.games.PlayersClient;
import com.google.android.gms.games.event.Event;
import com.google.android.gms.games.event.EventBuffer;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Task.*;
public class TTH_Activity extends SDLActivity
{
final static int LICENSE_REQUEST = 1;
native static void resume_after_showing_license();
native static void resume_after_showing_achievements();
native static void pause();
native static void resume();
// Client used to sign in with Google APIs
private GoogleSignInClient mGoogleSignInClient;
private AchievementsClient mAchievementsClient = null;
private boolean signin_failed = false;
// request codes we use when invoking an external activity
private static final int RC_UNUSED = 5001;
private static final int RC_SIGN_IN = 9001;
// This is so the screen is never cleared pure black, only shim::black (r:35, g:30, b:60)
static boolean paused = false;
private static final String TAG = "TTH";
#Override
public void onCreate(Bundle savedInstance)
{
super.onCreate(savedInstance);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == LICENSE_REQUEST) {
if (data != null) {
if (resultCode == RESULT_OK && data.getExtras().getString("MESSAGE").equals("OK")) {
show_license_result = 0;
}
else if (resultCode == RESULT_CANCELED && data.getExtras().getString("MESSAGE").equals("FAIL")) {
show_license_result = 1;
}
else {
show_license_result = 1;
}
}
else {
show_license_result = 1;
}
resume_after_showing_license();
}
if (requestCode == RC_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (result.isSuccess()) {
// The signed in account is stored in the result.
GoogleSignInAccount signedInAccount = result.getSignInAccount();
onConnected(signedInAccount);
}
else {
String message = result.getStatus().getStatusMessage();
if (message == null || message.isEmpty()) {
message = "An error occurred!";
}
new AlertDialog.Builder(this).setMessage(message).setNeutralButton(android.R.string.ok, null).show();
onDisconnected();
}
}
}
public void onStart() {
super.onStart();
}
#Override
public void onStop()
{
super.onStop();
pause();
}
#Override
public void onRestart()
{
super.onRestart();
resume();
}
#Override
public void onResume()
{
super.onResume();
signInSilently();
}
#Override
public void onPause()
{
super.onPause();
mAchievementsClient = null;
}
#Override
public void onPostResume()
{
super.onPostResume();
paused = true;
}
public void logString(String s)
{
Log.d("TTH", s);
}
public String getAppdataDir()
{
return getFilesDir().getAbsolutePath();
}
public String getSDCardDir()
{
File f = getExternalFilesDir(null);
if (f != null) {
return f.getAbsolutePath();
}
else {
return getFilesDir().getAbsolutePath();
}
}
static int show_license_result;
public void showLicense()
{
show_license_result = -1;
Intent intent = new Intent(this, License_Viewer_Activity.class);
startActivityForResult(intent, LICENSE_REQUEST);
}
public int getShowLicenseResult()
{
return show_license_result;
}
/*
public void openURL(String url)
{
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
}
*/
public void rumble(int milliseconds)
{
Vibrator v = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
if (v != null && v.hasVibrator()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(milliseconds, VibrationEffect.DEFAULT_AMPLITUDE));
}
else {
v.vibrate(milliseconds);
}
}
}
public boolean has_touchscreen()
{
return getPackageManager().hasSystemFeature("android.hardware.touchscreen");
}
public boolean has_vibrator()
{
Vibrator v = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
if (v != null) {
return v.hasVibrator();
}
else {
return false;
}
}
public void start_draw()
{
if (paused) {
paused = false;
}
}
public String get_android_language()
{
return Locale.getDefault().getLanguage();
}
private static File[] list_dir_files = null;
public void list_dir_start(String path)
{
try {
int slash = path.lastIndexOf('/');
final String glob = path.substring(slash+1).replace("*", ".*"); // +1 works even if not found (-1+1 == 0)
String dir = path.substring(0, slash);
File f = new File(dir);
list_dir_files = f.listFiles(new FileFilter() {
public boolean accept(File f)
{
try {
if (f.getName().matches(glob)) {
return true;
}
else {
return false;
}
}
catch (Exception e) {
Log.d("TTH", "list_dir_start FileFilter throwing " + e.getMessage());
return false;
}
}
});
}
catch (Exception e) {
list_dir_files = null;
Log.d("TTH", "list_dir_start throwing " + e.getMessage());
}
}
public String list_dir_next()
{
if (list_dir_files == null) {
return "";
}
else if (list_dir_files.length == 0) {
list_dir_files = null;
return "";
}
else {
File f = list_dir_files[0];
String name = f.getName();
if (list_dir_files.length == 1) {
list_dir_files = null;
}
else {
File[] new_list = new File[list_dir_files.length-1];
for (int i = 1; i < list_dir_files.length; i++) {
new_list[i-1] = list_dir_files[i];
}
list_dir_files = new_list;
}
return name;
}
}
private static final String ARC_DEVICE_PATTERN = ".+_cheets|cheets_.+";
public boolean is_chromebook()
{
// Google uses this, so should work?
return Build.DEVICE != null && Build.DEVICE.matches(ARC_DEVICE_PATTERN);
}
private static final int RC_ACHIEVEMENT_UI = 9003;
public boolean show_achievements()
{
if (mAchievementsClient == null) {
return false;
}
mAchievementsClient.getAchievementsIntent().addOnSuccessListener(new OnSuccessListener<Intent>() {
#Override
public void onSuccess(Intent intent) {
startActivityForResult(intent, RC_ACHIEVEMENT_UI);
resume_after_showing_achievements();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(Exception e) {
resume_after_showing_achievements();
}
}).addOnCompleteListener(new OnCompleteListener<Intent>() {
#Override
public void onComplete(Task<Intent> task) {
resume_after_showing_achievements();
}
});
return true;
}
public void achieve(String id)
{
if (mAchievementsClient != null) {
mAchievementsClient.unlock(id);
}
}
private void startSignInIntent() {
GoogleSignInClient signInClient = GoogleSignIn.getClient(this, GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN);
Intent intent = signInClient.getSignInIntent();
startActivityForResult(intent, RC_SIGN_IN);
}
private void signInSilently() {
if (signin_failed == true || mAchievementsClient != null) {
return;
}
GoogleSignInOptions signInOptions = GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN;
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
if (GoogleSignIn.hasPermissions(account, signInOptions.getScopeArray())) {
// Already signed in.
// The signed in account is stored in the 'account' variable.
//GoogleSignInAccount signedInAccount = account;
onConnected(account);
}
else {
// Haven't been signed-in before. Try the silent sign-in first.
GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOptions);
signInClient.silentSignIn().addOnCompleteListener(
this,
new OnCompleteListener<GoogleSignInAccount>() {
#Override
public void onComplete(#NonNull Task<GoogleSignInAccount> task) {
if (task.isSuccessful()) {
// The signed in account is stored in the task's result.
GoogleSignInAccount signedInAccount = task.getResult();
onConnected(signedInAccount);
}
else {
// Player will need to sign-in explicitly using via UI.
// See [sign-in best practices](http://developers.google.com/games/services/checklist) for guidance on how and when to implement Interactive Sign-in,
// and [Performing Interactive Sign-in](http://developers.google.com/games/services/android/signin#performing_interactive_sign-in) for details on how to implement
// Interactive Sign-in.
startSignInIntent();
}
}
}
);
}
}
public void start_google_play_games_services() {
/*
runOnUiThread(new Runnable() {
public void run() {
signInSilently();
}
});
*/
}
private void onConnected(GoogleSignInAccount googleSignInAccount) {
Log.d(TAG, "onConnected(): connected to Google APIs");
GamesClient gamesClient = Games.getGamesClient(this, googleSignInAccount);
gamesClient.setViewForPopups(findViewById(android.R.id.content));
gamesClient.setGravityForPopups(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
mAchievementsClient = Games.getAchievementsClient(this, googleSignInAccount);
}
private void onDisconnected() {
Log.d(TAG, "onDisconnected()");
mAchievementsClient = null;
signin_failed = true;
}
}
I have written an android app which basically allows me to keep track of times and address of GPS coordinates.
I have 3 Lists each corresponding to Lyft, Uber and Other.
But I believe my app starts slowing down my Smart Phone (Samsung Galaxy S7 Edge, with Android O)
can someone look at my code and tell me why is it slowing my smart phone.
My assumption is that, possibly thread synchronization issue.
Attached is my code
1) MainActivity.java
package com.milind.myapp.gpstrackingservice;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.PowerManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.ActionMode;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements AddressListener
{
private static final String TAG = MainActivity.class.getSimpleName();
private PowerManager.WakeLock wakeLock;
private TextView labelAddress;
private TextView multiTextLyft;
private TextView multiTextUber;
private TextView multiTextOther;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
labelAddress = findViewById(R.id.label_address);
multiTextLyft = findViewById(R.id.multi_text_lyft);
multiTextUber = findViewById(R.id.multi_text_uber);
multiTextOther = findViewById(R.id.multi_text_other);
if (MyService.isServiceStarted())
{
MyService.getInstance().load(getSharedPrefs());
refreshAllViews();
}
PowerManager powerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "myapp:My Lock");
}
#Override
protected void onStart()
{
super.onStart();
ActivityCompat.requestPermissions(this, new String[]
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WAKE_LOCK}, 1);
if (!MyService.isServiceStarted())
{
Intent intent = new Intent(this, MyService.class);
intent.setAction(MyService.ACTION_START_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
startForegroundService(intent);
}
else
{
startService(intent);
}
}
}
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
if (hasFocus)
{
if (MyService.isServiceStarted())
{
MyService.getInstance().registerAddressListener(this);
}
wakeLock.acquire();
}
else
{
if (MyService.isServiceStarted())
{
MyService.getInstance().unregisterAddressListener(this);
}
wakeLock.release();
}
}
public void onRequestPermissionsResult(int requestCode, String permissions[],
int[] grantResults)
{
switch (requestCode)
{
case 1:
{
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
}
else
{
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
#Override
public void onLocationChanged(Location loc)
{
final String address = MyService.getAddress(this, loc);
final CharSequence text = labelAddress.getText();
if (text.toString().equals(address))
{
return;
}
MyService.getInstance().load(getSharedPrefs());
labelAddress.setText(address);
refreshAllViews();
new Tone().play(880);
}
private void refreshAllViews()
{
runOnUiThread(new Runnable()
{
public void run()
{
refereshEditTextLyft();
refereshEditTextUber();
refereshEditTextOther();
}
});
}
private void refereshEditTextLyft()
{
multiTextLyft.setText(MyService.getInstance().getLyftAddresses());
}
private void refereshEditTextUber()
{
multiTextUber.setText(MyService.getInstance().getUberAddresses());
}
private void refereshEditTextOther()
{
multiTextOther.setText(MyService.getInstance().getOtherAddresses());
}
private SharedPreferences getSharedPrefs()
{
return getSharedPreferences("name", MODE_PRIVATE);
}
public void onLyftButtonClicked(View view)
{
MyService.getInstance().addLyftAddress(labelAddress.getText());
new Tone().play(440);
refereshEditTextLyft();
MyService.getInstance().save(getSharedPrefs());
}
public void onUberButtonClicked(View view)
{
MyService.getInstance().addUberAddress(labelAddress.getText());
new Tone().play(440);
refereshEditTextUber();
MyService.getInstance().save(getSharedPrefs());
}
public void onOtherButtonClicked(View view)
{
MyService.getInstance().addOtherAddress(labelAddress.getText());
new Tone().play(440);
refereshEditTextOther();
MyService.getInstance().save(getSharedPrefs());
}
public void onClearButtonClicked(View view)
{
if (MyService.isServiceStarted())
{
SharedPreferences sharedPreferences = getSharedPrefs();
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
editor.commit();
MyService.getInstance().clear();
refereshEditTextLyft();
refereshEditTextUber();
refereshEditTextOther();
}
}
public void onDelLyftButtonClicked(View view)
{
MyService.getInstance().delLyftEntry();
new Tone().play(440);
refereshEditTextLyft();
MyService.getInstance().save(getSharedPrefs());
}
public void onDelUberButtonClicked(View view)
{
MyService.getInstance().delUberEntry();
new Tone().play(440);
refereshEditTextUber();
MyService.getInstance().save(getSharedPrefs());
}
public void onDelOtherButtonClicked(View view)
{
MyService.getInstance().delOtherEntry();
new Tone().play(440);
refereshEditTextOther();
MyService.getInstance().save(getSharedPrefs());
}
#Override
protected void onRestart()
{
super.onRestart();
}
#Override
public void onActionModeFinished(ActionMode mode)
{
super.onActionModeFinished(mode);
}
#Override
public void onBackPressed()
{
super.onBackPressed();
}
}
2) The MyService.java
package com.milind.myapp.gpstrackingservice;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class MyService extends Service implements LocationListener
{
private static final String TAG = MyService.class.getSimpleName();
public static final String ACTION_START_SERVICE = "ACTION_START_SERVICE";
public static final String ACTION_STOP_SERVICE = "ACTION_STOP_SERVICE";
public static final String ACTION_UBER = "ACTION_UBER";
public static final String ACTION_LYFT = "ACTION_UBER";
public static final String ACTION_END = "ACTION_END";
public static final String LYFT_PREFIX = "Lyft";
public static final String OTHER_PREFIX = "Other";
public static final String UBER_PREFIX = "Uber";
private static MyService mInstance = null;
private List<AddressListener> listeners = new ArrayList<>();
private List<AddressPoint> lyftAddresses = new ArrayList<>();
private List<AddressPoint> uberAddresses = new ArrayList<>();
private List<AddressPoint> otherAddresses = new ArrayList<>();
private Location mLastLocation;
public MyService()
{
super();
Log.d(TAG, "MyService(): constructor called");
}
public static boolean isServiceStarted()
{
Log.d(TAG, "isServiceStarted()");
return mInstance != null;
}
public static final MyService getInstance()
{
return mInstance;
}
#Override
public IBinder onBind(Intent intent)
{
Log.d(TAG, "onBind(Intent intent)");
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d(TAG, "onStartCommand(Intent, flags, startId) : " + hashCode());
Log.d(TAG, "onStartCommand(...) intent=" + intent + "=" + ", flags=" + flags + ", startId=" + startId);
Log.d(TAG, "onStartCommand(...) isServiceStarted=" + isServiceStarted());
String action = null;
if (intent != null)
{
Log.d(TAG, intent.toString());
action = intent.getAction();
}
else
{
Log.d(TAG, "onStartCommand(...): early return");
return super.onStartCommand(intent, flags, startId);
}
if (isServiceStarted() == false && action == ACTION_START_SERVICE)
{
Log.d(TAG, "onStartCommand(...): Service starting=" + startId);
//startForegroundServivceNotification()
startRunningInForeground();
requestLocationUpdates();
mInstance = this;
Log.d(TAG, "onStartCommand(...): Service started=" + startId);
}
else if (isServiceStarted() == true && action == ACTION_STOP_SERVICE)
{
Log.d(TAG, "onStartCommand(...): Service stopping=" + startId);
stopLocationUpdates();
stopSelf();
Log.d(TAG, "onStartCommand(...): Service stop requested" + startId);
mInstance = null;
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy()
{
Log.d(TAG, "onDestroy(): Service destroyed");
super.onDestroy();
mInstance = null;
}
private void stopLocationUpdates()
{
Log.d(TAG, "stopLocationUpdates()");
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.removeUpdates(this);
}
private void requestLocationUpdates()
{
Log.d(TAG, "requestLocationUpdates()");
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
try
{
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 1500, 0, this);
Log.w(TAG, "requestLocationUpdates(): ended gracefully");
}
catch (SecurityException ex)
{
Log.w(TAG, "requestLocationUpdates(): Exception");
ex.printStackTrace();
}
}
#Override
public void onLocationChanged(Location location)
{
Log.v(TAG, "onLocationChanged(Location location): started, location=" + location.toString());
dispatchLocationChange(location);
mLastLocation = location;
Log.v(TAG, "onLocationChanged: completed");
}
private void dispatchLocationChange(Location loc)
{
Log.v(TAG, "dispatchLocationChange(Location)");
for (AddressListener listener : listeners)
{
listener.onLocationChanged(loc);
}
}
public static String getAddress(Context context, Location loc)
{
Log.v(TAG, "getAddress(Location loc) started");
List<Address> addresses;
Geocoder gcd = new Geocoder(context, Locale.getDefault());
try
{
addresses = gcd.getFromLocation(loc.getLatitude(),
loc.getLongitude(), 1);
String strReturnAddress = "";
if (addresses != null && addresses.size() > 0)
{
final Address address = addresses.get(0);
Log.d(TAG, address.toString());
String addressLines = "";
Log.v(TAG, "Locale: " + address.getLocale());
for (int i = 0; i <= address.getMaxAddressLineIndex(); ++i)
{
Log.v(TAG, "AddressLine " + i + ": " + address.getAddressLine(i));
addressLines += address.getAddressLine(i) + ", ";
Log.v(TAG, "addressLines:" + addressLines);
}
String strAddress =
addressLines
;
Log.v(TAG, "strAddress:" + strAddress);
strReturnAddress = strAddress.substring(0, strAddress.length() - 2);
Log.v(TAG, "strReturnAddress:" + strReturnAddress);
}
Log.d(TAG, "getAddress(Location loc) completed with return=" + strReturnAddress);
return strReturnAddress;
}
catch (IOException e)
{
e.printStackTrace();
Log.d(TAG, "Exception", e);
}
Log.d(TAG, "getAddress(Location loc) completed with return=null");
return "";
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
Log.d(TAG, "onStatusChanged(provider, status, extras): status=" + status + ", extras=" + extras);
}
#Override
public void onProviderEnabled(String provider)
{
Log.d(TAG, "onProviderEnabled(provider) ");
}
#Override
public void onProviderDisabled(String provider)
{
Log.d(TAG, "onProviderDisabled(provider) ");
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
private static void logGetProperties(final String tag, final Object obj)
{
Log.v(tag, "logGetProperties(...)");
Class cls = obj.getClass();
Method[] methods = cls.getMethods();
Log.v(tag, "methods.length = " + methods.length);
for (Method method : methods)
{
String methodName = method.getName();
Log.v(tag, "methodName = " + methodName);
if (methodName.startsWith("get")
&& (method.getParameters() == null || method.getParameters().length == 0)
&& method.getReturnType() != Void.class)
{
try
{
Log.v(tag, methodName + " = " + method.invoke(obj, new Object[0]));
}
catch (Exception ex)
{
Log.e(tag, methodName + " Failed (exception)");
}
}
}
}
public AddressListener registerAddressListener(AddressListener listener)
{
Log.d(TAG, "registerAddressListener(AddressListener)");
if (!listeners.contains(listener))
{
listeners.add(listener);
}
return listener;
}
public AddressListener unregisterAddressListener(AddressListener listener)
{
Log.d(TAG, "unregisterAddressListener(AddressListener)");
if (listeners.contains(listener))
{
listeners.remove(listener);
Log.d(TAG, "unregisterAddressListener(AddressListener): Listener removed");
return listener;
}
Log.d(TAG, "unregisterAddressListener(AddressListener): Listener not found");
return null;
}
public void addLyftAddress(CharSequence text)
{
Log.d(TAG, "addLyftAddress(CharSequence text): text: " + text);
lyftAddresses.add(new AddressPoint(System.currentTimeMillis(), text));
}
public void addUberAddress(CharSequence text)
{
Log.d(TAG, "addUberAddress(CharSequence text): text: " + text);
uberAddresses.add(new AddressPoint(System.currentTimeMillis(), text));
}
public void addOtherAddress(CharSequence text)
{
Log.d(TAG, "addOtherAddress(CharSequence text): text: " + text);
otherAddresses.add(new AddressPoint(System.currentTimeMillis(), text));
}
String getLyftAddresses()
{
return getAddresses(lyftAddresses);
}
String getUberAddresses()
{
return getAddresses(uberAddresses);
}
String getOtherAddresses()
{
return getAddresses(otherAddresses);
}
private String getAddresses(List<AddressPoint> addresses)
{
Log.d(TAG, "getAddresses(List<AddressPoint>)");
String strAddresses = "" + addresses.size() + "\n--------\n";
for (int i = 0; i < addresses.size(); ++i)
{
AddressPoint addresspoint = addresses.get(i);
strAddresses += addresspoint + "\n--------\n";
if ((i % 2) != 0)
{
strAddresses += "\n\n";
}
}
return strAddresses;
}
private void startRunningInForeground()
{
//if more than or equal to 26
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
//if more than 26
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
{
String CHANNEL_ONE_ID = "Package.Service";
String CHANNEL_ONE_NAME = "Screen service";
NotificationChannel notificationChannel = null;
notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,
CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_MIN);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setShowBadge(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (manager != null)
{
manager.createNotificationChannel(notificationChannel);
}
Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground);
Notification notification = new Notification.Builder(getApplicationContext())
.setChannelId(CHANNEL_ONE_ID)
.setContentTitle("Recording data")
.setContentText("App is running background operations")
.setSmallIcon(R.drawable.ic_launcher_background)
.setLargeIcon(icon)
.build();
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);
startForeground(101, notification);
}
//if version 26
else
{
startForeground(101, updateNotification());
}
}
//if less than version 26
else
{
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("App")
.setContentText("App is running background operations")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setOngoing(true).build();
startForeground(101, notification);
}
}
private Notification updateNotification()
{
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
return new NotificationCompat.Builder(this)
.setContentTitle("Activity log")
.setTicker("Ticker")
.setContentText("app is running background operations")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pendingIntent)
.setOngoing(true).build();
}
public void load(final SharedPreferences lSharedPrefs)
{
Log.w(TAG, "load(SharedPreferences): started");
load(lSharedPrefs, lyftAddresses, LYFT_PREFIX);
load(lSharedPrefs, uberAddresses, UBER_PREFIX);
load(lSharedPrefs, otherAddresses, OTHER_PREFIX);
Log.w(TAG, "load(SharedPreferences): completed");
}
private void load(final SharedPreferences lSharedPrefs, final List<AddressPoint> lAddrPoints, final String lPrefix)
{
Log.w(TAG, "load(SharedPreferences, lAddrPoints, lPrefix)");
lAddrPoints.clear();
final int count = lSharedPrefs.getInt(lPrefix + "Count", lAddrPoints.size());
for (int i = 0; i < count; ++i)
{
String address = lSharedPrefs.getString(lPrefix + "Address" + i, null);
final long time = lSharedPrefs.getLong(lPrefix + "Time" + i, 0);
//if address or time is invalid skip to the next entry
if (address == null || time == 0)
{
continue;
}
final AddressPoint addressPoint = new AddressPoint(time, address);
lAddrPoints.add(addressPoint);
}
}
private void save(final SharedPreferences lSharedPrefs, final List<AddressPoint> lAddrPoints, final String lPrefix)
{
Log.w(TAG, "save(SharedPreferences, lAddrPoints, lPrefix)");
SharedPreferences.Editor editor = lSharedPrefs.edit();
final int count = lAddrPoints.size();
//Save the count
editor.putInt(lPrefix + "Count", count);
for (int i = 0; i < count; ++i)
{
//Save the entry
AddressPoint lAddrPoint = lAddrPoints.get(i);
editor.putLong(lPrefix + "Time" + i, lAddrPoint.getTime());
editor.putString(lPrefix + "Address" + i, (String) lAddrPoint.getAddress());
}
Log.w(TAG, "save(sharedFrefs, List, String): commit");
editor.commit();
}
public void save(final SharedPreferences sharedPreferences)
{
Log.w(TAG, "save(SharedPreferences): started");
Log.w(TAG, "save: lyftAddresses");
save(sharedPreferences, lyftAddresses, LYFT_PREFIX);
Log.w(TAG, "save: uberAddresses");
save(sharedPreferences, uberAddresses, UBER_PREFIX);
Log.w(TAG, "save: otherAddresses");
save(sharedPreferences, otherAddresses, OTHER_PREFIX);
Log.w(TAG, "save(SharedPreferences) completed");
}
public void clear()
{
lyftAddresses.clear();
uberAddresses.clear();
otherAddresses.clear();
}
public void delLyftEntry()
{
if (lyftAddresses.size() > 0)
{
lyftAddresses.remove(lyftAddresses.size() - 1);
}
}
public void delUberEntry()
{
if (uberAddresses.size() > 0)
{
uberAddresses.remove(uberAddresses.size() - 1);
}
}
public void delOtherEntry()
{
if (otherAddresses.size() > 0)
{
otherAddresses.remove(otherAddresses.size() - 1);
}
}
}
3) activity_main.xml
4) AndroidManifest.xml
This (likely) isn't a threading issue, in the normal sense of the word. What's happening is you've got a GeoCoder.getFromLocation() call executing on the main thread. Per the documentation:
The returned values may be obtained by means of a network lookup. ...It may be useful to call this method from a thread separate from your primary UI thread.
That means the method could block for several seconds each time it is called. That's more likely if you're driving through an area of spotty cell coverage. Since the method is called with each location update (roughly every 2 seconds), it's understandable that the UI is hanging.
SUGGESTED FIX
Replace your getAddress() function with an AsyncTask, which moves the getFromLocation() call to a background thread (now your app will truly be multithreaded). Something like this should work:
private class GetFromLocationTask extends AsyncTask<Location, Void, List<Address>> {
protected List<Address> doInBackground(Location... locs) {
return gcd.getFromLocation(locs[ 0 ].getLatitude(), locs[ 0 ].getLongitude(), 1);
}
protected void onProgressUpdate(Void... progress) {}
protected void onPostExecute(List<Address> result) {
//execute the remainder of your getAddress() logic here
}
}
Then, execute it using new GetFromLocationTask().execute(location). Call this instead of getAddress(). You don't need to pass a Context to getAddress(), since Service.this will work just as well (it is a Context).
Bonus hint: Note that onLocationChanged() runs on the UI thread, and so does refreshAllViews(). That means your call to runOnUiThread() is superfluous, and it will just execute the given Runnable synchronously.
This is a continuation from my previous quesion. I wanted to open the pdf in the app instead of opening it with third-party apps. I've rewritten the code so that pdf files in assets folder can be copied into sd card.
Here is my code:
package com.dell.pdfreader;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import net.sf.andpdf.pdfviewer.PdfViewerActivity;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class PdfMainActivity extends AppCompatActivity implements View.OnClickListener {
private static String TAG = PdfMainActivity.class.getCanonicalName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pdf_main);
Button click = (Button) findViewById(R.id.click);
click.setOnClickListener(this);
}
#Override
public void onClick(View view) {
Context mContext = getApplicationContext();
switch (view.getId()) {
case R.id.click:
try {
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("pdffiles");
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
for (String fileName : files != null ? files : new String[0]) {
InputStream is = null;
OutputStream os = null;
try {
is = assetManager.open("pdffiles/" + fileName);
os = new FileOutputStream(Environment.getExternalStorageDirectory().toString() + "/" + fileName);
copyFile(is, os);
is.close();
os.flush();
os.close();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
Uri path = Uri.parse(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "Dojo_lab_tour.pdf");
String oPath = path.toString();
Intent intent = new Intent(PdfMainActivity.this, ReaderActivity.class);
if (ContextCompat.checkSelfPermission(PdfMainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
intent.setDataAndType(path, "application/pdf");
intent.putExtra(PdfViewerActivity.EXTRA_PDFFILENAME, oPath);
startActivity(intent);
} else {
Log.d(TAG, "No permission!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void copyFile(InputStream is, OutputStream os) throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = is.read(buffer)) != -1) {
os.write(buffer, 0, read);
}
}
}
And here is my 2nd activity:
package com.dell.pdfreader;
import android.os.Bundle;
public class ReaderActivity extends net.sf.andpdf.pdfviewer.PdfViewerActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reader);
}
#Override
public int getPreviousPageImageResource() {
return R.drawable.left_arrow;
}
#Override
public int getNextPageImageResource() {
return R.drawable.right_arrow;
}
#Override
public int getZoomInImageResource() {
return R.drawable.zoom_in;
}
#Override
public int getZoomOutImageResource() {
return R.drawable.zoom_out;
}
#Override
public int getPdfPasswordLayoutResource() {
return 0;
}
#Override
public int getPdfPageNumberResource() {
return 0;
}
#Override
public int getPdfPasswordEditField() {
return 0;
}
#Override
public int getPdfPasswordOkButton() {
return 0;
}
#Override
public int getPdfPasswordExitButton() {
return 0;
}
#Override
public int getPdfPageNumberEditField() {
return 0;
}
}
When I run that code, I get this error:
03-05 16:19:43.000 14997-14997/com.dell.pdfreader E/com.dell.pdfreader.PdfMainActivity: /storage/emulated/0/Dojo_Lab_Tour.pdf (Permission denied)
03-05 16:19:43.049 14997-14997/com.dell.pdfreader I/PDFVIEWER: onCreate
03-05 16:19:43.049 14997-14997/com.dell.pdfreader E/PDFVIEWER: restoreInstance
03-05 16:19:43.119 14997-14997/com.dell.pdfreader I/PDFVIEWER: Intent { dat=/storage/emulated/0/Dojo_lab_tour.pdf typ=application/pdf cmp=com.dell.pdfreader/.ReaderActivity (has extras) }
03-05 16:19:43.124 14997-14997/com.dell.pdfreader I/PDFVIEWER: ST='file '/storage/emulated/0/Dojo_lab_tour.pdf' not found'
In mainfest file, I've added these two lines:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
How can I fix this error?
EDIT:
My assets folder structure is as given below:
I modified my code as suggested by Tommin and Commonsware:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
Intent intent = new Intent(PdfMainActivity.this, ReaderActivity.class);
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
intent.setDataAndType(path, "application/pdf");
intent.putExtra(PdfViewerActivity.EXTRA_PDFFILENAME, oPath);
startActivity(intent);
} else {
Log.d(TAG, "No permission!");
}
}
Getting this error now:
03-05 17:45:26.526 7888-7888/com.dell.pdfreader E/com.dell.pdfreader.PdfMainActivity: /storage/emulated/0/Dojo_Lab_Tour.pdf (Permission denied)
1- Add the permissions in your manifest, like you did:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.....">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
2- These 2 permissions are considered to be dangerous permissions, which you should request on the Runtime, on your onClick method for ex:
#Override
public void onClick (View view) {
if (ContextCompat.checkSelfPermission (PdfMainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission (PdfMainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions (PdfMainActivity.this, new String [] { Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE }, 1000);
return;
}
...
}
3- Make sure the external storage is writable before copying your stream into it:
if (!isExternalStorageWritable ()) {
throw new Exception ("External Storage Not Writable");
}
private boolean isExternalStorageWritable () {
return Environment.MEDIA_MOUNTED.equals (Environment.getExternalStorageState ());
}
4- Your code becomes:
#Override
public void onClick (View v) {
if (ContextCompat.checkSelfPermission (PdfMainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission (PdfMainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions (PdfMainActivity.this, new String [] { Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE }, 1000);
return;
}
AssetManager assetManager = getAssets ();
String dir = "pdffiles";
try {
String [] paths = assetManager.list (dir);
for (String path : paths) {
if (!isExternalStorageWritable ()) {
throw new Exception ("External Storage Not Writable");
}
InputStream is = assetManager.open (dir + File.separator + path);
OutputStream os = new FileOutputStream (Environment.getExternalStorageDirectory () + File.separator + path);
copy (is, os);
closeQuietly (os, is);
}
} catch (Exception e) {
// TODO Catch your exception here
}
}
public static int copy (InputStream is, OutputStream os) throws IOException {
long count = 0;
int n;
byte [] buffer = new byte [4 * 1024];
while (-1 != (n = is.read (buffer))) {
os.write (buffer, 0, n);
count += n;
}
if (count > Integer.MAX_VALUE) {
return -1;
}
return (int) count;
}
public static void closeQuietly (Closeable... closeables) {
if (closeables == null || closeables.length == 0) {
return;
}
try {
for (Closeable closeable : closeables) {
if (closeable != null) {
closeable.close ();
}
}
} catch (final IOException ignore) { }
}
5- When trying to read the PDFs, make sure the external storage is readable as well by calling:
private boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState ();
return Environment.MEDIA_MOUNTED.equals (state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals (state);
}
6- Put the copy processing on a background thread not to block the UI. And maybe show a progress Popup to the user.
I got it, guys. I modified my code as:
Uri path = Uri.parse(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "EPSF.pdf");
String oPath = path.toString();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
&& checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) {
ActivityCompat.requestPermissions(PdfMainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1000);
Log.d(TAG, "No permission!");
} else {
Intent intent1 = new Intent(PdfMainActivity.this, ReaderActivity.class);
intent1.setDataAndType(path, "application/pdf");
intent1.putExtra(PdfViewerActivity.EXTRA_PDFFILENAME, oPath);
startActivity(intent1);
}
}
I added run time permissions and modified according to what Mehdi had suggested.
I am developing an app to uploading ,displaying and downloading files from G Drive. Unfortunately When downloading I am getting
com.google.api.client.http.HttpResponseException: 401 Unauthorized.
Please help me to solve this problem.
Here I am assigning
credential = GoogleAccountCredential.usingOAuth2(this,DriveScopes.DRIVE);
service=new Drive.Builder(AndroidHttp.newCompatibleTransport(),new GsonFactory(),credential).build();
My Code Is:
package com.example.googledrive;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
import com.google.api.client.http.FileContent;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.Drive.Children;
import com.google.api.services.drive.Drive.Files;
import com.google.api.services.drive.Drive.Files.Get;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.ChildList;
import com.google.api.services.drive.model.ChildReference;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.FileList;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import android.provider.MediaStore;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends Activity {
static final int REQUEST_ACCOUNT_PICKER = 1;
static final int REQUEST_AUTHORIZATION = 2;
static final int CAPTURE_IMAGE = 3;
private static Uri fileUri;
private static Drive service;
private ProgressDialog progressDialog;
private GoogleAccountCredential credential;
String fileId;
String fileName;
String downloadUrl;
ListView listView;
Activity activity;
String sdCardPadth;
List<File> allFileList;
ArrayList<String> fileType;
ArrayList<String> mainTitleList;
ArrayList<String> fileIdList;
ArrayList<String> alternateUrlList;
ArrayList<Integer> fileSizeList;
FileTitlesAdapter myAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.uploadedFilesList);
allFileList = new ArrayList<File>();
mainTitleList = new ArrayList<String>();
alternateUrlList = new ArrayList<String>();
fileSizeList = new ArrayList<Integer>();
fileType = new ArrayList<String>();
fileIdList=new ArrayList<String>();
progressDialog=new ProgressDialog(getApplicationContext());
progressDialog.setTitle("Please Wait....");
progressDialog.setCancelable(false);
activity = this;
credential = GoogleAccountCredential.usingOAuth2(this,DriveScopes.DRIVE);
startActivityForResult(credential.newChooseAccountIntent(),REQUEST_ACCOUNT_PICKER);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View view, final int arg2,long arg3) {
// String str=itemArray.get(arg2).toString().trim();
System.out.println("mainTitleList size==="+mainTitleList.size());
System.out.println("arg2==="+arg2);
fileName = (String)mainTitleList.get(arg2);
mainTitleList.clear();
//fileSizeList.clear();
final String fileTypeStr=fileType.get(arg2);
fileType.clear();
if(fileTypeStr.contains("application/vnd.google-apps.folder"))
{
Thread t = new Thread(new Runnable() {
#Override
public void run() {
boolean b=true;
try {
String dirUrl=alternateUrlList.get(arg2);
alternateUrlList.clear();
System.out.println("Folder Name Is:"+fileName);
System.out.println("Folder Type Is:"+fileTypeStr);
System.out.println("Folder URL Is:"+dirUrl);
String fileId=fileIdList.get(arg2);
System.out.println("Folder Id Is:"+fileId);
//retrieveAllFilesFromDir(service, fileId, b);
//retrieveAllFiles1(service, b, fileId);
//Files.List request = service.children().get(fileId, null);
Files.List request = service.files().list().setQ("'" + fileId + "' in parents ");
retrieveAllFiles(service,request,b);
//retrieveAllFiles(service, b);
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("Exception In retrieveAllFiles Dir Is:"+e);
e.printStackTrace();
}
}
});t.start();
}
else
{
try {
System.out.println("fileSizeList size===="+fileSizeList.size());
System.out.println("arg2===="+arg2);
Integer fileSize = (int) fileSizeList.get(arg2);
downloadUrl = alternateUrlList.get(arg2);
byte[] size = new byte[fileSize];
int byteRead = 0, byteWritten = 0;
sdCardPadth = Environment.getExternalStorageDirectory().getPath();
System.out.println("Download Url==="+downloadUrl);
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
InputStream inStream=downloadFile(service, downloadUrl);
java.io.File inFile=new java.io.File(sdCardPadth+"/"+fileName+"1");
System.out.println("File Succesfully Stored");
}
}).start();
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("Exception In get Integer Is:" + e);
e.printStackTrace();
}
}
}
});
}
#Override
protected void onActivityResult(final int requestCode,
final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_ACCOUNT_PICKER:
if (resultCode == RESULT_OK && data != null
&& data.getExtras() != null) {
String accountName = data
.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
if (accountName != null) {
credential.setSelectedAccountName(accountName);
service = getDriveService(credential);
final boolean b=false;
Thread t=new Thread(new Runnable() {
#Override
public void run() {
try
{
Files.List request = service.files().list().setQ("hidden="+b);
retrieveAllFiles(service,request,b);
} catch (Exception e) {
System.out.println("Exception Is:"+e);
e.printStackTrace();
}
}
}) ;t.start();
}
}
break;
case REQUEST_AUTHORIZATION:
if (resultCode == Activity.RESULT_OK) {
System.out.println("REQUEST_AUTHORIZATION case Is:"
+ REQUEST_AUTHORIZATION);
saveFileToDrive();
} else {
startActivityForResult(credential.newChooseAccountIntent(),
REQUEST_ACCOUNT_PICKER);
}
break;
case CAPTURE_IMAGE:
if (resultCode == Activity.RESULT_OK) {
System.out.println("CAPTURE_IMAGE case Is:" + CAPTURE_IMAGE);
saveFileToDrive();
}
}
}
private void saveFileToDrive() {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
// File's binary content
System.out.println("run method");
java.io.File fileContent = new java.io.File(fileUri.getPath());
FileContent mediaContent = new FileContent("image/jpeg",fileContent);
// File's metadata.
File body = new File();
body.setTitle(fileContent.getName());
body.setMimeType("image/jpeg");
File file=null;
try {
file = service.files().insert(body, mediaContent).execute();
} catch (Exception e) {
System.out.println("Exception In Insert File Is"+e);
e.printStackTrace();
}
if (file != null) {
showToast("Photo uploaded: " + file.getTitle());
System.out.println("photo sucessfullly uploaded:"+ fileId);boolean b=false;
Files.List request = service.files().list().setQ("hidden="+b);
retrieveAllFiles(service,request,b);
}
} catch (UserRecoverableAuthIOException e) {
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
}
private Drive getDriveService(GoogleAccountCredential credential) {
return new Drive.Builder(AndroidHttp.newCompatibleTransport(),
new GsonFactory(), credential).build();
}
public void showToast(final String toast) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), toast,Toast.LENGTH_SHORT).show();
}
});
}
private List<File> retrieveAllFiles(Drive service,Files.List request,boolean b) throws IOException {
List<File> result = new ArrayList<File>();
final ArrayList<String> titleList = new ArrayList<String>();
String fileUrl = "";
do {
try {
FileList files = request.execute();
result.addAll(files.getItems());
request.setPageToken(files.getNextPageToken());
for (int i = 0; i < result.size(); i++) {
File tempFile = result.get(i);
String fileTypeStr = tempFile.getMimeType();
String fileName = tempFile.getTitle();
titleList.add(fileName);
fileId = tempFile.getId();
fileIdList.add(fileId);
fileUrl = tempFile.getAlternateLink();
System.out.println("<><>< fileUrl Is:" + fileUrl);
alternateUrlList.add(fileUrl);
fileType.add(fileTypeStr);
mainTitleList.add(fileName);
try {
Integer fileSize =tempFile.getFileSize()==null?100:(int) (long) tempFile.getFileSize();
fileSizeList.add(fileSize);
System.out.println("<><>< fileSize Is:" + fileSize);
} catch (Exception e) {
fileSizeList.add(2000);
e.printStackTrace();
}
}
try {
runOnUiThread(new Runnable() {
public void run() {
myAdapter = new FileTitlesAdapter(activity,
fileType, mainTitleList, alternateUrlList,
fileSizeList);
listView.setAdapter(myAdapter);
}
});
} catch (Exception e) {
System.out.println("Exception Setting ListView Is:" + e);
e.printStackTrace();
}
} catch (IOException e) {
System.out.println("An error occurred in retrieveAllFiles:"+ e);
request.setPageToken(null);
}
} while (request.getPageToken() != null
&& request.getPageToken().length() > 0);
return result;
}
private static InputStream downloadFile(Drive service, String url) {
System.out.println("downloadFile is called service=="+service);
if (url != null && url.length() > 0) {
try {
System.out.println("downloadFile is called try");
HttpResponse resp =service.getRequestFactory().buildGetRequest(new GenericUrl(url)).execute();
System.out.println("resp.getContent()===="+resp.getContent());
return resp.getContent();
} catch (Exception e) {
System.out.println("Exception Is:"+e);
e.printStackTrace();
return null;
}
} else {
System.out.println("No Exception No Output");
return null;
}
}
}
This is code that I use to download File from google Drive
new AsyncTask<Void, Integer, Boolean>() {
#Override
protected Boolean doInBackground(Void... params) {
try {
File file = service.files().get("path in drive").execute();
java.io.File toFile = new java.io.File("where you want to store");
toFile.createNewFile();
HttpDownloadManager downloader = new HttpDownloadManager(file, toFile);
downloader.setListener(new HttpDownloadManager.FileDownloadProgressListener() {
public void downloadProgress(long bytesRead, long totalBytes) {
Log.i("chauster",totalBytes);
Log.i("chauster",bytesRead);
}
#Override
public void downloadFinished() {
// TODO Auto-generated method stub
}
#Override
public void downloadFailedWithError(Exception e) {
// TODO Auto-generated method stub
}
});
return downloader.download(service);
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
protected void onPostExecute(Boolean result) {
};
}.execute();
HttpDownloadManager.java
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpResponse;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.File;
import com.grandex.ShareInfomation.ShareData;
import com.grandex.ShareInfomation.ShareData.ToolTapState;
public class HttpDownloadManager {
private String donwloadUrl;
private String toFile;
private FileDownloadProgressListener listener;
private long totalBytes;
public void setListener(FileDownloadProgressListener listener) {
this.listener = listener;
}
public HttpDownloadManager(File sourceFile, java.io.File destinationFile) {
super();
this.donwloadUrl = sourceFile.getDownloadUrl();
this.toFile = destinationFile.toString();
this.totalBytes = sourceFile.getFileSize();
}
public static interface FileDownloadProgressListener {
public void downloadProgress(long bytesRead, long totalBytes);
public void downloadFinished();
public void downloadFailedWithError(Exception e);
}
public boolean download(Drive service) {
HttpResponse respEntity = null;
try {
// URL url = new URL(urlString);
respEntity = service.getRequestFactory()
.buildGetRequest(new GenericUrl(donwloadUrl)).execute();
InputStream in = respEntity.getContent();
if(totalBytes == 0) {
totalBytes = respEntity.getContentLoggingLimit();
}
try {
FileOutputStream f = new FileOutputStream(toFile) {
#Override
public void write(byte[] buffer, int byteOffset,
int byteCount) throws IOException {
// TODO Auto-generated method stub
super.write(buffer, byteOffset, byteCount);
}
}
};
byte[] buffer = new byte[1024];
int len1 = 0;
long bytesRead = 0;
while ((len1 = in.read(buffer)) > 0) {
f.write(buffer, 0, len1);
if (listener != null) {
bytesRead += len1;
listener.downloadProgress(bytesRead, totalBytes);
}
}
f.close();
} catch (Exception e) {
if (listener != null) {
listener.downloadFailedWithError(e);
}
return false;
}
if (listener != null) {
listener.downloadFinished();
}
return true;
} catch (IOException ex) {
if (listener != null) {
listener.downloadFailedWithError(ex);
return false;
}
} finally {
if(respEntity != null) {
try {
respEntity.disconnect();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return false;
}
}
Nowhere in your code are you setting the Authorization header.
You need something like
setRequestProperty("Authorization", "OAuth " + "***ACCESS_TOKEN***");
For any 401/403 errors it's well worth getting your request working on the Oauth. Try this out
Please check below code for download apk file from google drive
implementation 'com.google.android.material:material:1.0.0'
Add uses permission
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
Create a file provider
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<files-path
name="files"
path="." />
Now declare the file provider inside the manifest
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_provider_paths" />
Add some value inside strings.xml file
<resources>
<string name="app_name">Download APK</string>
<string name="downloading">Downloading...</string>
<string name="title_file_download">APK is downloading</string>
<string name="storage_access_required">Storage access is required to downloading the file.</string>
<string name="storage_permission_denied">Storage permission request was denied.</string>
<string name="ok">OK</string>
Create a download controller
package com.hktpayment.mytmoney.pos.mauritius.util
import android.app.Dialog
import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.util.Log
import android.widget.ProgressBar
import android.widget.Toast
import androidx.core.content.FileProvider
import com.hktpayment.mytmoney.pos.mauritius.BuildConfig
import com.hktpayment.mytmoney.pos.mauritius.R
import java.io.File
class DownloadController(
private val context: Context,
private val url: String,
private val progressBar: Dialog
) {
companion object {
private const val FILE_NAME = "SampleDownloadApp.apk"
private const val FILE_BASE_PATH = "file://"
private const val MIME_TYPE = "application/vnd.android.package-archive"
private const val PROVIDER_PATH = ".provider"
private const val APP_INSTALL_PATH = "application/vnd.android.package-
archive"
}
private lateinit var downloadManager: DownloadManager
fun enqueueDownload() {
var destination =
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString()
+ "/"
destination += FILE_NAME
val uri = Uri.parse("$FILE_BASE_PATH$destination")
val file = File(destination)
if (file.exists()) file.delete()
downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as
DownloadManager
val downloadUri = Uri.parse(url)
val request = DownloadManager.Request(downloadUri)
request.setMimeType(MIME_TYPE)
request.setTitle(context.getString(R.string.title_file_download))
request.setDescription(context.getString(R.string.downloading))
// set destination
request.setDestinationUri(uri)
showInstallOption(destination, uri)
// Enqueue a new download and same the referenceId
downloadManager.enqueue(request)
Toast.makeText(context, context.getString(R.string.downloading),
Toast.LENGTH_LONG)
.show()
}
private fun showInstallOption(
destination: String,
uri: Uri
) {
// set BroadcastReceiver to install app when .apk is downloaded
progressBar.show()
val onComplete = object : BroadcastReceiver() {
override fun onReceive(
context: Context,
intent: Intent
) {
progressBar.dismiss()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val contentUri = FileProvider.getUriForFile(
context,
BuildConfig.APPLICATION_ID + PROVIDER_PATH,
File(destination)
)
val install = Intent(Intent.ACTION_VIEW)
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
install.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
install.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
install.data = contentUri
context.startActivity(install)
context.unregisterReceiver(this)
// finish()
} else {
val install = Intent(Intent.ACTION_VIEW)
install.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
install.setDataAndType(
uri,
APP_INSTALL_PATH
)
context.startActivity(install)
context.unregisterReceiver(this)
// finish()
}
}
}
context.registerReceiver(onComplete, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
}
}
In this activity, we are checking storage permission first. If permission is granted than calling download function otherwise requesting for storage permission.
val apkUrl = "https://download .apk"
downloadController = DownloadController(this, apkUrl)
downloadController.enqueueDownload()
I have recently implement wifi direct into my project,my aim is pass string value between two wifidirect connected devices when some of my app condition satisfies.right now i have listed all peers and also made connection between the selected peer.what my idea is to pass a json file between the devices.so before try to execute that idea i try to pass a image file between two devices.i followed the steps from the android wifidirect tutorial.listing peers and the connection between the peers is success full but i cant pass the data between the devices.the follwing is my code.
FileTransferService.java
package jing.app.directwifi;
import android.app.IntentService;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
/**
* A service that process each file transfer request i.e Intent by opening a
* socket connection with the WiFi Direct Group Owner and writing the file
*/
public class FileTransferService extends IntentService {
private static final int SOCKET_TIMEOUT = 5000;
public static final String ACTION_SEND_FILE = "jing.app.directwifi.SEND_FILE";
public static final String EXTRAS_FILE_PATH = "file_url";
public static final String EXTRAS_GROUP_OWNER_ADDRESS = "go_host";
public static final String EXTRAS_GROUP_OWNER_PORT = "go_port";
public FileTransferService(String name) {
super(name);
}
public FileTransferService() {
super("FileTransferService");
}
/*
* (non-Javadoc)
* #see android.app.IntentService#onHandleIntent(android.content.Intent)
*/
#Override
protected void onHandleIntent(Intent intent) {
Context context = getApplicationContext();
if (intent.getAction().equals(ACTION_SEND_FILE)) {
String fileUri = intent.getExtras().getString(EXTRAS_FILE_PATH);
String host = intent.getExtras().getString(EXTRAS_GROUP_OWNER_ADDRESS);
Socket socket = new Socket();
int port = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);
try {
// Log.d(WiFiDirectActivity.TAG, "Opening client socket - ");
socket.bind(null);
socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);
Log.d("connected", "Client socket - " + socket.isConnected());
OutputStream stream = socket.getOutputStream();
ContentResolver cr = context.getContentResolver();
InputStream is = null;
try {
is = cr.openInputStream(Uri.parse(fileUri));
} catch (FileNotFoundException e) {
Log.d("exp", e.toString());
}
MainActivity.copyFile(is, stream);
Log.d("exp" ,"Client: Data written");
} catch (IOException e) {
Log.e("exp", e.getMessage());
} finally {
if (socket != null) {
if (socket.isConnected()) {
try {
socket.close();
} catch (IOException e) {
// Give up
e.printStackTrace();
}
}
}
}
}
}
}
Main Activity.java
package jing.app.directwifi;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collection;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener, android.content.DialogInterface.OnClickListener, ConnectionInfoListener {
private WifiP2pManager mManager;
private Channel mChannel;
private BroadcastReceiver mReceiver;
private IntentFilter mIntentFilter;
private Button mDiscover;
private TextView mDevices;
public ArrayAdapter mAdapter;
private ArrayList<WifiP2pDevice> mDeviceList = new ArrayList<WifiP2pDevice>();
protected static final int CHOOSE_FILE_RESULT_CODE = 20;
int flag=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDiscover = (Button) findViewById(R.id.discover);
mDiscover.setOnClickListener(this);
mDevices = (TextView) findViewById(R.id.peers);
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, getMainLooper(), null);
mReceiver = new WiFiDirectReceiver(mManager, mChannel, this);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(mReceiver, mIntentFilter);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
private class WiFiDirectReceiver extends BroadcastReceiver {
private WifiP2pManager mManager;
private Channel mChannel;
private MainActivity mActivity;
public WiFiDirectReceiver(WifiP2pManager manager, Channel channel, MainActivity activity) {
super();
mManager = manager;
mChannel = channel;
mActivity = activity;
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
String title = "ANDROID_ID[" + getAndroid_ID() + "]";
title += " MAC[" + getMACAddress() + "]";
Toast.makeText(mActivity, "Wi-Fi Direct is enabled."+title, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(mActivity, "Wi-Fi Direct is disabled.", Toast.LENGTH_SHORT).show();
}
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
if (mManager != null) {
mManager.requestPeers(mChannel, new PeerListListener() {
#Override
public void onPeersAvailable(WifiP2pDeviceList peers) {
if (peers != null) {
mDeviceList.addAll(peers.getDeviceList());
ArrayList<String> deviceNames = new ArrayList<String>();
for (WifiP2pDevice device : mDeviceList) {
deviceNames.add(device.deviceName);
}
if (deviceNames.size() > 0) {
mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1, deviceNames);
if(flag==0)
{
flag=1;
showDeviceListDialog();
}
} else {
Toast.makeText(mActivity, "Device list is empty.", Toast.LENGTH_SHORT).show();
}
}
}
});
}
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
}
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.discover:
onDiscover();
break;
}
}
private void onDiscover() {
mManager.discoverPeers(mChannel, new ActionListener() {
#Override
public void onSuccess() {
Toast.makeText(MainActivity.this, "Discover peers successfully.", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(int reason) {
Toast.makeText(MainActivity.this, "Discover peers failed.", Toast.LENGTH_SHORT).show();
}
});
}
private void showDeviceListDialog() {
DeviceListDialog deviceListDialog = new DeviceListDialog();
deviceListDialog.show(getFragmentManager(), "devices");
}
private class DeviceListDialog extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Select a device")
.setSingleChoiceItems(mAdapter, 0, MainActivity.this)
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
return builder.create();
}
}
#Override
public void onClick(DialogInterface dialog, int which) {
onDeviceSelected(which);
dialog.dismiss();
}
private void onDeviceSelected(int which) {
WifiP2pDevice device = mDeviceList.get(which);
if (device == null) {
return;
}
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
mManager.connect(mChannel, config, new ActionListener() {
#Override
public void onSuccess() {
Toast.makeText(MainActivity.this, "Connected", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, CHOOSE_FILE_RESULT_CODE);
}
#Override
public void onFailure(int reason) {
Toast.makeText(MainActivity.this, "Failed to connect", Toast.LENGTH_SHORT).show();
}
});
}
/**
* ANDROID_ID
*/
private String getAndroid_ID() {
return Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
}
/**
* Wi-Fi MAC
*/
private String getMACAddress() {
WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = manager.getConnectionInfo();
String mac = wifiInfo.getMacAddress();
// After the group negotiation, we assign the group owner as the file
// server. The file server is single threaded, single connection server
// socket.
new FileServerAsyncTask(getApplicationContext())
.execute();
return mac;
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// User has picked an image. Transfer it to group owner i.e peer using
// FileTransferService.
Uri uri = data.getData();
Log.d("intent", "Intent----------- " + uri);
Intent serviceIntent = new Intent(MainActivity.this, FileTransferService.class);
serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE);
serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH, uri.toString());
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS,
getMACAddress());
serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT, 8988);
startService(serviceIntent);
}
/**
* A simple server socket that accepts connection and writes some data on
* the stream.
*/
public static class FileServerAsyncTask extends AsyncTask<Void, Void, String> {
private Context context;
/**
* #param context
* #param statusText
*/
public FileServerAsyncTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(Void... params) {
try {
System.out.println("insideeeeeeeeeeeeeeeeeeeeeeee");
ServerSocket serverSocket = new ServerSocket(8988);
Log.d("Server: Socket opened", "Server: Socket opened");
Socket client = serverSocket.accept();
Log.d("Server: connection done", "Server: connection done");
final File f = new File(Environment.getExternalStorageDirectory() + "/"
+ context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis()
+ ".jpg");
File dirs = new File(f.getParent());
if (!dirs.exists())
dirs.mkdirs();
f.createNewFile();
Log.d("server: copying files ", "server: copying files " + f.toString());
InputStream inputstream = client.getInputStream();
copyFile(inputstream, new FileOutputStream(f));
serverSocket.close();
return f.getAbsolutePath();
} catch (IOException e) {
Log.e("exp", e.getMessage());
System.out.println(":iooo:"+e);
return null;
}
}
/*
* (non-Javadoc)
* #see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
#Override
protected void onPostExecute(String result) {
if (result != null) {
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + result), "image/*");
context.startActivity(intent);
}
}
/*
* (non-Javadoc)
* #see android.os.AsyncTask#onPreExecute()
*/
#Override
protected void onPreExecute() {
}
}
public static boolean copyFile(InputStream inputStream, OutputStream out) {
byte buf[] = new byte[1024];
int len;
long startTime=System.currentTimeMillis();
try {
while ((len = inputStream.read(buf)) != -1) {
out.write(buf, 0, len);
}
out.close();
inputStream.close();
long endTime=System.currentTimeMillis()-startTime;
Log.v("","Time taken to transfer all bytes is : "+endTime);
} catch (IOException e) {
Log.d("exp", e.toString());
return false;
}
return true;
}
#Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "connectioninfoo", 3000).show();
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jing.app.directwifi"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="16" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Market filtering -->
<uses-feature
android:name="android.hardware.wifi.direct"
android:required="true" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="jing.app.directwifi.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Used for transferring files after a successful connection -->
<service
android:name=".FileTransferService"
android:enabled="true" />
</application>
</manifest>
These are files used in my code .form the tutorial i have found that
new FileServerAsyncTask(getApplicationContext())
.execute();
where the the incomming data is begin accepted so when i need to execute this asyn thread,so anyone help me in which portion i have made the mistake.how can i transfer the file between devices .
The android code from the demo wifi direct project is able to pass file is unidirectional. ie. you can send file from client to server only. You need furthur modifications to make it work in both direction.
EDIT 2:
For that you need to know the IP address of both connected peers. Use the following function which I made following various sources with my modifications wherever appropriate.
public static String getIpAddress() {
try {
List<NetworkInterface> interfaces = Collections
.list(NetworkInterface.getNetworkInterfaces());
/*
* for (NetworkInterface networkInterface : interfaces) { Log.v(TAG,
* "interface name " + networkInterface.getName() + "mac = " +
* getMACAddress(networkInterface.getName())); }
*/
for (NetworkInterface intf : interfaces) {
if (!getMACAddress(intf.getName()).equalsIgnoreCase(
Globals.thisDeviceAddress)) {
// Log.v(TAG, "ignore the interface " + intf.getName());
// continue;
}
if (!intf.getName().contains("p2p"))
continue;
Log.v(TAG,
intf.getName() + " " + getMACAddress(intf.getName()));
List<InetAddress> addrs = Collections.list(intf
.getInetAddresses());
for (InetAddress addr : addrs) {
// Log.v(TAG, "inside");
if (!addr.isLoopbackAddress()) {
// Log.v(TAG, "isnt loopback");
String sAddr = addr.getHostAddress().toUpperCase();
Log.v(TAG, "ip=" + sAddr);
boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
if (isIPv4) {
if (sAddr.contains("192.168.49.")) {
Log.v(TAG, "ip = " + sAddr);
return sAddr;
}
}
}
}
}
} catch (Exception ex) {
Log.v(TAG, "error in parsing");
} // for now eat exceptions
Log.v(TAG, "returning empty ip address");
return "";
}
public static String getMACAddress(String interfaceName) {
try {
List<NetworkInterface> interfaces = Collections
.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface intf : interfaces) {
if (interfaceName != null) {
if (!intf.getName().equalsIgnoreCase(interfaceName))
continue;
}
byte[] mac = intf.getHardwareAddress();
if (mac == null)
return "";
StringBuilder buf = new StringBuilder();
for (int idx = 0; idx < mac.length; idx++)
buf.append(String.format("%02X:", mac[idx]));
if (buf.length() > 0)
buf.deleteCharAt(buf.length() - 1);
return buf.toString();
}
} catch (Exception ex) {
} // for now eat exceptions
return "";
/*
* try { // this is so Linux hack return
* loadFileAsString("/sys/class/net/" +interfaceName +
* "/address").toUpperCase().trim(); } catch (IOException ex) { return
* null; }
*/
}
I think the way you initialize client makes the problem.
You need to call this
new FileServerAsyncTask(getApplicationContext()).execute();
after the connection is established and check if it's a client.
Now you are creating a client socket only if it is a server(group owner) and always when you call to get a MAC address.
So on the client side you are not intializing the socket and so not able to receive the file.
Once check the WifiDirect sample demo provided in the SDK, you may get more idea.