Showing posts with label android-intent. Show all posts
Showing posts with label android-intent. Show all posts

Monday, June 25, 2018

Intent.ACTION_VIEW - Multiple files

Leave a Comment

I have a requirement to show multiple files (2 or more each of images, music or video, but only one type). Given a series of thumbnails or filenames, the user should be able to select a chekbox and preview the selection. IF the user selects multiple images, I want to be able to show ONLY those images selected. If he selects multiple mp3 files, I want to be able to play ONLY those songs.

If the user selects only one file, that's easy to do:

Intent i = new Intent(Intent.ACTION_VIEW);    if (someType == IMAGE) {    i.setDataAndType(Uri.fromFile(imageFile),"image/*"); } else     if (sometype == VIDEO) {       i.setDataAndType(Uri.fromFile(videoFile),"video/mp4");    }    else if (someType == MUSIC) {        i.setDataAndType(Uri.fromFile(musicFile),"audio/mpeg");    }   startActivity(i); 

However, if the user selects two or more of one type, how can I architect the intent to use whatever image/audio/video apps the user may have installed? Don't want to write custom players/viewers as I know an existing app can do this.

I am trying to mimic the functionality of a cloud app called "AllShare Play" (https://www.samsung.com/us/2012-allshare-play/) . This app does exactly what I need to do in my app - allows the user to "preview" multiple files and uses just the standard "Gallery" app for images, standard music app for songs, etc. In each case, only the files selected are shown or played using standard apps each Android device is loaded with, so I know it's possible to do without writing a viewer or player.

Anyone have any ideas how to send multiple files via Intent.ACTION_VIEW to an external app?

1 Answers

Answers 1

There is no android standard for send multible to ACTION_VIEW.

But there is a standard for ACTION_SEND_MULTIPLE where the files are transfered via EXTRA_STREAM.

for a working sendmultible example see Secure-Photo-Viewer: you select multible images from a gallery app and send them to Secure-Photo-Viewer.

If your app is the only sender and receiver of this intent you can use the same mechanism with ACTION_VIEW, too.

To learn more on intent communication you can use the intent-intercept app that allows sending and receiving many types of intents

here is the code i use to send multible images

        Intent sendIntent = new Intent();         sendIntent.setType("image/*");         if (selectionCount == 1) {             Long imageId = mSelectedItems.first();             sendIntent.setAction(Intent.ACTION_SEND);             sendIntent.putExtra(EXTRA_STREAM, getUri(imageId));         } else {             sendIntent.setAction(Intent.ACTION_SEND_MULTIPLE);              ArrayList<Uri> uris = new ArrayList<Uri>();              for (Long mSelectedItem : mSelectedItems) {                 uris.add(getUri(mSelectedItem));             }             sendIntent.putParcelableArrayListExtra(EXTRA_STREAM, uris);         }         startActivity(sendIntent); 
Read More

Tuesday, December 19, 2017

Picking a picture either from photos or multimedia, but not by recent images

Leave a Comment

I would like to pick picture similar to whatsapp:

Code:

   public void pickImage()     {         if (Build.VERSION.SDK_INT <19)         {             Intent pickPhoto = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);               Intent intent = new Intent();             intent.setType("image/*");             intent.setAction(Intent.ACTION_GET_CONTENT);             startActivityForResult(Intent.createChooser(intent, "Select Picture"), SELECT_PICTURE);         } else {             Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);             intent.addCategory(Intent.CATEGORY_OPENABLE);             intent.setType("image/*");             startActivityForResult(intent, KITKAT_SELECT_PICTURE);          }     }      @Override     protected void onActivityResult(int requestCode, int resultCode, Intent data) {         super.onActivityResult(requestCode, resultCode, data);          if (resultCode != Activity.RESULT_OK) return;         if (null == data) return;         Uri originalUri = null;         if (requestCode == SELECT_PICTURE)         {             originalUri = data.getData();         }         else if (requestCode == KITKAT_SELECT_PICTURE)         {             originalUri = data.getData();             final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);             // Check for the freshest data.             getContentResolver().takePersistableUriPermission(originalUri, takeFlags);         }     } 

Question:

The above can pick pictures and then showing pic properly in an imageview. However, during the picking process, it messes up the pictures photoed by camera (called album) and pictures in other media, and is sorted by most recent images.

How could i make it similar to whatsapp, picking image from a folder containing only but all images taken from camera, or a folder containing all other multimedia, INSTEAD OF messing up camera photos and mutimedia pictures by most recently added?

Thank you.

2 Answers

Answers 1

Use MediaStore.Images.Media.query function with order by set DSC DATE_ADDED field. You can set content URI for internal/external storage based on your requirement.

Answers 2

Try this hope so it will be helpful my problem was fix out with help of this code..

Uri selectedImageURI = data.getData(); imageFile = new File(getRealPathFromURI(selectedImageURI)); 

and:

private String getRealPathFromURI(Uri contentURI) {     String result;     Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);     if (cursor == null) { // Source is Dropbox or other similar local file path         result = contentURI.getPath();     } else {          cursor.moveToFirst();          int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);          result = cursor.getString(idx);         cursor.close();     }     return result; } 
Read More

Tuesday, November 14, 2017

Start activity from service takes too long

Leave a Comment

I have a Service that when one function gives to me true it will start a new Activity but it takes like 5 seconds...

I've read about this issue, and I've found on StackOverflow this example to "avoid" this bug..

Intent intent = new Intent(this, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0); try {    pendingIntent.send(); } catch (PendingIntent.CanceledException e) {    e.printStackTrace(); } 

but sadly it doesn't start the Activity faster, I don't need to be inmmediate (better if it's possible), but I don't want to wait +5 seconds to launch the new Activity, do you knwo any trick to avoid this?

I'm using PendingIntent because I've found that guy that said that it should solve this issue : Starting an activity from a service after HOME button pressed without the 5 seconds delay

Note

If I press back button it launch it autommatically, 0 delay, but I'm looking pressing the home button.

2 Answers

Answers 1

I cannot comment everywhere yet, so I'm putting this solution of a similar problem as an answer

After much digging, found out the cause of the problem. Apparently it's not a bug, it is a feature which does not allow Services or BroadcastReceivers to launch activities for up to 5 seconds after home button is pressed. No easy way to overcome this.

More info here: https://code.google.com/p/android/issues/detail?id=4536

I replaced the activity with a Window added to the window manager of the running service. This does not cause any delay.

Source link Stackoverflow

Answers 2

First thing we cannot update any UI related stuff in service, neither calling activity nor updating any UI elements, 
Same problem i too have faced.

Then i have used EventBus library to communicate UI elements from service 
Below is the sample example

public class SendSPLocationService extends Service { Handler mHandler = new Handler(); Thread downloadThread; boolean isRunning = true; private VolleyHelper volleyHelper;  @Override public IBinder onBind(Intent intent) {     // TODO Auto-generated method stub     return null; }  @Override public void onCreate() {     //  Toast.makeText(this, " MyService Created ", Toast.LENGTH_LONG).show();     volleyHelper = new VolleyHelper(this);  }  @Override public int onStartCommand(Intent intent, int flags, int startId) {     final Timer t = new Timer();     t.schedule(new TimerTask() {         @Override         public void run() {             Log.d("run: ", "service is running!");              try {                                         EventBus.getDefault().post(new FutureJobEvent(false, error.networkResponse.statusCode, errorJson.getString("message")));              } catch (JSONException e) {                 e.printStackTrace();             }             // t.cancel();             Log.d("run: ", "service is stopped!");          }     }, 0, 5000);     return START_STICKY; } } 

Use below code for triggered event to observe..either in activity/fragment

@Override public void onStart() {     super.onStart();     if (!EventBus.getDefault().isRegistered(this))         EventBus.getDefault().register(this); }  @Override public void onStop() {     super.onStop();     if (EventBus.getDefault().isRegistered(this))         EventBus.getDefault().unregister(this); }  @Subscribe(threadMode = ThreadMode.MAIN)  public void onMessageEvent(TrackSPEvent event) {     if (event.success) {          startActivity(new Intent(this,MainActivity.class));  }  } 
Read More

Monday, September 25, 2017

Could not launch intent within 45 seconds. Perhaps the main thread has not gone idle within a reasonable amount of time?

Leave a Comment

I am writing Espresso Test. Here is the test case

OnClick of Fab, the app launches QuizActivity.

Let me explain to you little about my app.

So the app requirement was -

  1. There is JSON file in assets folder
  2. I have to parse it and store the data in database
  3. On Main Activity load this data from database into recyclerview. There is Fab button, on click of it app pass a random list of data (which I have loaded in recyclerview) to QuizActivity

Here is how I did coding -

  1. In MainActivity's onCreate() used AsyncTask to parse and insert data into database only once.
  2. Once data is available, loaded it in recyclerview via AsyncTaskLoader
  3. set Onclick listener on Fab. and passed required data to QuizActivity.

Below is my test

@RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest {    /* @Rule     public IntentsTestRule<MainActivity> intentsTestRule =             new IntentsTestRule<MainActivity>(MainActivity.class); */      @Rule     public ActivityTestRule<MainActivity> intentsTestRule =             new ActivityTestRule<MainActivity>(MainActivity.class,false,true);      @Test     public void fabTest(){         onView(withId(R.id.fab)).perform(click());         //Check if the text_question textview is displayed         onView(withId(R.id.text_question)).check(matches(isDisplayed()));     }     /* @Test     public void clickFloatingActionButton() {         onView(withId(R.id.fab))                 .perform(click());         intended(hasComponent(new ComponentName(getTargetContext(), QuizActivity.class)));     }*/ } 

My approach is -

  1. Find Fab
  2. Perform click
  3. Check if the text_question textview is displayed. Note this textview is on QuizActivity.

After I run the test I am getting

java.lang.RuntimeException: Could not launch intent Intent { act=android.intent.action.MAIN flg=0x14000000 cmp=my_package_name/.MainActivity } within 45 seconds. Perhaps the main thread has not gone idle within a reasonable amount of time? There could be an animation or something constantly repainting the screen. Or the activity is doing network calls on creation? See the threaddump logs. For your reference the last time the event queue was idle before your activity launch request was 1505287862579 and now the last time the queue went idle was: 1505287862579. If these numbers are the same your activity might be hogging the event queue.

PS - I have turned off all the animations. I don't have progress bar in code.

Also one more note , if I comment out the AsyncTask, AsyncTaskLoader, RecyclerView part in onCreate() method then the test is passing.

I suspect that it might be causing due to background task.

Anyone faced similar problem? Please let me know if you know the solution. I am struggling from two days. I searched for similar threads on stackoverflow but nothing worked for me.

1 Answers

Answers 1

I finally got the solution!

Actually, the culprit was custom view in my adapter.

Espresso waits until the AsyncTask or AsyncTaskLoader loads the data, but it looks like custom view causing this problem as stated in the exception :

the main thread has not gone idle within a reasonable amount of time? There could be an animation or something constantly repainting the screen.

Anyways to overcome this problem, what I need to do is -

"If the test is running set the visibility of Custom view to GONE"

How would you do that?

 private AtomicBoolean isTestRunning;      public synchronized boolean isTestRunning () {         if (null == isTestRunning) {             boolean istest;              try {                  Class.forName ("Full path of your TestName"); // for e.g. com.example.MyTest                  istest = true;             } catch (ClassNotFoundException e) {                 istest = false;             }              isTestRunning = new AtomicBoolean (istest);         }          return isRunningTest.get ();     } 

Now here I am using Recyclerview so in ViewHolder,

public InsectHolder(View itemView)         {             super(itemView);                        customView = (DangerLevelView) itemView.findViewById(R.id.danger_level_tv);              if(isRunningTest()) {                 customView.setVisibility(View.GONE);             }         } 

And yay! your test will be passed.

Hope someone finds it helpful!

Please let me know if you have any questions in comment section below!

Read More

Friday, July 21, 2017

Xamarin Android: How to Share PDF File From Assets Folder? Via Whatsapp I get message, the file you picked was not a document

Leave a Comment

I use Xamarin Android. I have a PDF File storaged in Assest folder from Xamarin Android.

enter image description here

I want to share this file in whatsapp, but I recive a message: "the file you picked was not a document"

enter image description here

I tried two ways:

This is the first way

var SendButton = FindViewById<Button>(Resource.Id.SendButton); SendButton.Click += (s, e) =>                  {                 ////Create a new file in the exteranl storage and copy the file from assets folder to external storage folder                 Java.IO.File dstFile = new Java.IO.File(Environment.ExternalStorageDirectory.Path + "/my-pdf-File--2017.pdf");                 dstFile.CreateNewFile();                  var inputStream = new FileInputStream(Assets.OpenFd("my-pdf-File--2017.pdf").FileDescriptor);                 var outputStream = new FileOutputStream(dstFile);                 CopyFile(inputStream, outputStream);                  //to let system scan the audio file and detect it                 Intent intent = new Intent(Intent.ActionMediaScannerScanFile);                 intent.SetData(Uri.FromFile(dstFile));                 this.SendBroadcast(intent);                  //share the Uri of the file                 var sharingIntent = new Intent();                 sharingIntent.SetAction(Intent.ActionSend);                 sharingIntent.PutExtra(Intent.ExtraStream, Uri.FromFile(dstFile));                 sharingIntent.SetType("application/pdf");                  this.StartActivity(Intent.CreateChooser(sharingIntent, "@string/QuotationShare"));             }; 

This is the second

//Other way              var SendButton2 = FindViewById<Button>(Resource.Id.SendButton2);             SendButton2.Click += (s, e) =>             {                  Intent intent = new Intent(Intent.ActionSend);                 intent.SetType("application/pdf");                  Uri uri = Uri.Parse(Environment.ExternalStorageDirectory.Path + "/my-pdf-File--2017.pdf");                 intent.PutExtra(Intent.ExtraStream, uri);                  try                 {                     StartActivity(Intent.CreateChooser(intent, "Share PDF file"));                 }                 catch (System.Exception ex)                 {                     Toast.MakeText(this, "Error: Cannot open or share created PDF report. " + ex.Message, ToastLength.Short).Show();                 }             }; 

In other way, when I share via email the pdf file is sent empty, "corrupt file"

What can I do?

2 Answers

Answers 1

The solution is copying de .pdf file from assets folder to a local storage. Then We able to share de file.

First copy the file:

string fileName = "my-pdf-File--2017.pdf";  var localFolder = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath; var MyFilePath = System.IO.Path.Combine(localFolder, fileName);  using (var streamReader = new StreamReader(Assets.Open(fileName))) {        using (var memstream = new MemoryStream())        {               streamReader.BaseStream.CopyTo(memstream);               var bytes = memstream.ToArray();               //write to local storage               System.IO.File.WriteAllBytes(MyFilePath, bytes);                MyFilePath = $"file://{localFolder}/{fileName}";       } } 

Then share the file, from local storage:

var fileUri = Android.Net.Uri.Parse(MyFilePath);  var intent = new Intent(); intent.SetFlags(ActivityFlags.ClearTop); intent.SetFlags(ActivityFlags.NewTask); intent.SetAction(Intent.ActionSend); intent.SetType("*/*"); intent.PutExtra(Intent.ExtraStream, fileUri); intent.AddFlags(ActivityFlags.GrantReadUriPermission);  var chooserIntent = Intent.CreateChooser(intent, title); chooserIntent.SetFlags(ActivityFlags.ClearTop); chooserIntent.SetFlags(ActivityFlags.NewTask); Android.App.Application.Context.StartActivity(chooserIntent); 

Answers 2

the file you picked was not a document

I had this issue when I trying to share a .pdf file via WhatsApp from assets folder, but it gives me the same error as your question :

the file you picked was not a document 

Finally I got a solution that copy the .pdf file in assets folder to Download folder, it works fine :

var pathFile = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads);  Java.IO.File dstFile = new Java.IO.File(pathFile.AbsolutePath + "/my-pdf-File--2017.pdf"); 

Effect like this.

Read More

Tuesday, June 27, 2017

Android TTS checking for supported locale with missing/not downloaded voice data

Leave a Comment

I'm using Android's TextToSpeech class. Everything is working normally. However, there are languages/locales that aren't installed by default but supported by the TTS engine and I can't capture the state of missing voice data.

With the internet on, when I try to setLanguage to a new locale which its voice data hasn't been downloaded, it'll simply download the voice data and perform the speak method normally/successfully.

However, with internet off, when I try to setLanguage to a new locale which its voice data hasn't been downloaded, it attempts to download the voice data. But with no internet, it just indicates "downloading" on the "TTS voice data" settings screen under "Language and input" for the selected locale, without any progress. And as expected the speak method doesn't work since the voice data isn't downloaded. When this happens, I would think TTS methods setLanguage/isLanguageAvailable will return LANG_MISSING_DATA for me to capture this state, however, it simply returns LANG_COUNTRY_AVAILABLE. The situation is shown in this image: enter image description here

I want to be able to detect when the voice data of the locale being chosen isn't downloaded/missing and either give a toast message or direct user to download it. I have seen several posts suggesting the use of using isLanguageAvailable like this one. I also looked at the android documentation and it seems like isLanguageAvailable's return values should capture the state of missing voice data with LANG_MISSING_DATA.

I also tried sending an intent with ACTION_CHECK_TTS_DATA as the other way to check for missing data as suggested in the Android documentation I linked. However, the resultCode again didn't capture/indicate that the voice data is missing (CHECK_VOICE_DATA_FAIL) but returned CHECK_VOICE_DATA_PASS instead.

In this case, how should I capture the state of a language/locale being available/supported, with the voice data missing? I'm also curious why CHECK_VOICE_DATA_PASS and LANG_MISSING_DATA aren't the values returned. When the voice data is missing, shouldn't it return these values? Thanks! Below is the return value when I try to use setLanguage and isLanguageAvailable on locales that haven't had its voice data downloaded (0 and 1 are the returned value of the method shown in the logs, -1 is the one that corresponds to missing voice data): enter image description here

1 Answers

Answers 1

You can find all available Locale of the device using following function. hope this code will help you.

 Locale loc = new Locale("en");  Locale[] availableLocales= loc.getAvailableLocales();  Boolean available=Boolean.FALSE;  for (int i=0;i<availableLocales.length;i++)  {   if(availableLocales[i].getDisplayLanguage().equals("your_locale_language"))    {         available=Boolean.TRUE;         // TODO:      }  } 
Read More

Saturday, January 14, 2017

Google Sign in not working

Leave a Comment

I am following Google's documentation for Google Sign. Having a weird problem when I call

Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent (mGoogleApiClient);         startActivityForResult (signInIntent, RC_SIGN_IN); 

Its seems Intent has been fired but I can't see account picker dialog. I am using

compile "com.google.android.gms:play-services-auth:9.6.1"

When I check does googleclient object is connected, it returns true.

Implementation

@OnClick (R.id.google_singin_button) void signInButtonClicked () {      HashMap<String, Object> map = new HashMap<> ();     map.put (AllAnalytics.LABEL, AllAnalytics.Label.SIGN_IN_GOOGLE);     map.put (AllAnalytics.ACTION, AllAnalytics.Action.CLICK);     map.put (AllAnalytics.CATEGORY, AllAnalytics.Category.REGISTRATION_SCREEN);      aa.analyticsEventOccur (map);      if (null != mGoogleApiClient) {        // Log.e(TAG,mGoogleApiClient.isConnected()+"");         Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent (mGoogleApiClient);         startActivityForResult (signInIntent, RC_SIGN_IN);     } }  @Override public void onActivityResult (int requestCode, int resultCode, Intent data) {     super.onActivityResult (requestCode, resultCode, data);      // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);     if(Activity.RESULT_CANCELED != resultCode)     if (requestCode == RC_SIGN_IN) {         GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent (data);         handleSignInResult (result);     } }  @Override public void onCreate (Bundle savedInstanceState) {     super.onCreate (savedInstanceState);     mActivity = (RegisterActivity) getActivity ();     GoogleSignInOptions gso             = new GoogleSignInOptions.Builder (GoogleSignInOptions.DEFAULT_SIGN_IN)             .requestServerAuthCode (getString (R.string.google_client_auth), false)             .requestEmail ()             .build ();      mGoogleApiClient = new GoogleApiClient.Builder (getContext ())             .enableAutoManage (mActivity , this)             .addApi (Auth.GOOGLE_SIGN_IN_API, gso)             .build ();  } 

Log Cat

Class not found when unmarshalling: com.google.android.gms.auth.api.signin.internal.SignInConfiguration java.lang.ClassNotFoundException: com.google.android.gms.auth.api.signin.internal.SignInConfiguration    at java.lang.Class.classForName(Native Method)    at java.lang.Class.forName(Class.java:309)    at java.lang.Class.forName(Class.java:273)    at android.os.Parcel.readParcelableCreator(Parcel.java:2281)    at android.os.Parcel.readParcelable(Parcel.java:2245)    at android.os.Parcel.readValue(Parcel.java:2152)    at android.os.Parcel.readArrayMapInternal(Parcel.java:2485)    at android.os.BaseBundle.unparcel(BaseBundle.java:221)    at android.os.BaseBundle.containsKey(BaseBundle.java:269)    at android.content.Intent.hasExtra(Intent.java:4884)    at com.miui.server.XSpaceManagerService.isPublicIntent(XSpaceManagerService.java:174)    at com.android.server.am.ActivityStackSupervisorInjector.checkXSpaceControl(ActivityStackSupervisorInjector.java:56)    at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:897)    at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:3478)    at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3465)    at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:140)    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2245)    at android.os.Binder.execTransact(Binder.java:446) Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.android.gms.auth.api.signin.internal.SignInConfiguration" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)    at java.lang.ClassLoader.loadClass(ClassLoader.java:511)    at java.lang.ClassLoader.loadClass(ClassLoader.java:469)    at java.lang.Class.classForName(Native Method)     at java.lang.Class.forName(Class.java:309)     at java.lang.Class.forName(Class.java:273)     at android.os.Parcel.readParcelableCreator(Parcel.java:2281)     at android.os.Parcel.readParcelable(Parcel.java:2245)     at android.os.Parcel.readValue(Parcel.java:2152)     at android.os.Parcel.readArrayMapInternal(Parcel.java:2485)     at android.os.BaseBundle.unparcel(BaseBundle.java:221)     at android.os.BaseBundle.containsKey(BaseBundle.java:269)     at android.content.Intent.hasExtra(Intent.java:4884)     at com.miui.server.XSpaceManagerService.isPublicIntent(XSpaceManagerService.java:174)     at com.android.server.am.ActivityStackSupervisorInjector.checkXSpaceControl(ActivityStackSupervisorInjector.java:56)     at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:897)     at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:3478)     at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3465)     at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:140)     at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2245)     at android.os.Binder.execTransact(Binder.java:446)      Suppressed: java.lang.ClassNotFoundException: com.google.android.gms.auth.api.signin.internal.SignInConfiguration    at java.lang.Class.classForName(Native Method)    at java.lang.BootClassLoader.findClass(ClassLoader.java:781)    at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)    at java.lang.ClassLoader.loadClass(ClassLoader.java:504)         ... 19 more Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available  10-11 23:46:17.873 1387-4537/? E/JavaBinder: *** Uncaught remote exception!  (Exceptions are not yet supported across processes.) java.lang.RuntimeException: Parcel android.os.Parcel@33c1f490: Unmarshalling unknown type code 6684783 at offset 320    at android.os.Parcel.readValue(Parcel.java:2228)    at android.os.Parcel.readArrayMapInternal(Parcel.java:2485)    at android.os.BaseBundle.unparcel(BaseBundle.java:221)    at android.os.BaseBundle.containsKey(BaseBundle.java:269)    at android.content.Intent.hasExtra(Intent.java:4884)    at com.miui.server.XSpaceManagerService.shouldResolveAgain(XSpaceManagerService.java:145)    at com.android.server.am.ActivityStackSupervisorInjector.resolveXSpaceIntent(ActivityStackSupervisorInjector.java:68)    at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:898)    at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:3478)    at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3465)    at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:140)    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2245)    at android.os.Binder.execTransact(Binder.java:446)   10-11 23:46:17.873 1387-4537/? A/ActivityManager: Activity Manager Crash java.lang.RuntimeException: Parcel android.os.Parcel@33c1f490: Unmarshalling unknown type code 6684783 at offset 320     at android.os.Parcel.readValue(Parcel.java:2228)     at android.os.Parcel.readArrayMapInternal(Parcel.java:2485)     at android.os.BaseBundle.unparcel(BaseBundle.java:221)     at android.os.BaseBundle.containsKey(BaseBundle.java:269)     at android.content.Intent.hasExtra(Intent.java:4884)     at com.miui.server.XSpaceManagerService.shouldResolveAgain(XSpaceManagerService.java:145)     at com.android.server.am.ActivityStackSupervisorInjector.resolveXSpaceIntent(ActivityStackSupervisorInjector.java:68)     at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:898)     at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:3478)     at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3465)     at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:140)     at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2245)             at android.os.Binder.execTransact(Binder.java:446) 

3 Answers

Answers 1

Try to implement GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener on your activity and try code below

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)             .requestEmail()             .build();     google_api_client = new GoogleApiClient.Builder(LoginActivity.this)             .addConnectionCallbacks(LoginActivity.this)             .addOnConnectionFailedListener(LoginActivity.this)             .addApi(Plus.API)             .addScope(Plus.SCOPE_PLUS_PROFILE)             .addScope(Plus.SCOPE_PLUS_LOGIN)             .build();     if (google_api_client.isConnected()) {         google_api_client.connect();     }   @Override protected void onStart() {     super.onStart();     google_api_client.connect(); }   @Override protected void onStop() {     super.onStop();     if (google_api_client.isConnected()) {         google_api_client.disconnect();     } }   @Override public void onConnected(@Nullable Bundle bundle) {     if (google_api_client.isConnected() && is_gglSignInBtn_clicked) {         google_api_client.clearDefaultAccountAndReconnect();      }     if (is_gglSignInBtn_clicked) {         getProfileInfo();         is_gglSignInBtn_clicked = false;     } }  @Override public void onConnectionSuspended(int i) {     google_api_client.connect(); }  private void gPlusSignIn() {     if (!google_api_client.isConnecting()) {         if (is_gglSignInBtn_clicked && google_api_client.isConnected()) {             google_api_client.clearDefaultAccountAndReconnect();             getProfileInfo();         } else {             resolveSignInError();         }      }  }  @Override public void onConnectionFailed(@NonNull ConnectionResult result) {     if (!result.hasResolution()) {         google_api_availability.getErrorDialog(this, result.getErrorCode(), request_code).show();         return;     }     if (!is_intent_inprogress) {          connection_result = result;           if (is_gglSignInBtn_clicked) {             resolveSignInError();         }     }  }  private void resolveSignInError() {     if (connection_result != null) {         if (connection_result.hasResolution()) {             try {                 is_intent_inprogress = true;                 connection_result.startResolutionForResult(this, SIGN_IN_CODE);             } catch (IntentSender.SendIntentException e) {                 is_intent_inprogress = false;                 google_api_client.connect();             }         }     } }  private void getProfileInfo() {     try {         mProgressDialog.setMessage("Signing in....");         mProgressDialog.show();         if (Plus.PeopleApi.getCurrentPerson(google_api_client) != null) {             Person currentPerson = Plus.PeopleApi.getCurrentPerson(google_api_client);              Log.i("googleEmail", "" + (Plus.AccountApi.getAccountName(google_api_client)));             email = "" + (Plus.AccountApi.getAccountName(google_api_client));             setPersonalInfo(currentPerson);         } else {             Toast.makeText(getApplicationContext(),                     "No Personal info mention", Toast.LENGTH_LONG).show();             finish();         }      } catch (Exception e) {         e.printStackTrace();     }  }  private void setPersonalInfo(Person currentPerson) {      try {         JSONObject googleJsonObject = new JSONObject(currentPerson + "");         familyName = googleJsonObject.getJSONObject("name").optString("familyName");         givenName = googleJsonObject.getJSONObject("name").optString("givenName");         gender = googleJsonObject.optString("gender");         displayName = googleJsonObject.optString("displayName");         googleId = googleJsonObject.optString("id");         imageUrl = "http://res.cloudinary.com/demo/image/gplus/" + googleId + ".jpg";      } catch (JSONException e) {         e.printStackTrace();     } 

Answers 2

Just check your onActivityResult() is called or not because you have used Fragment. So you have to pass the Activity result from activity to fragment.

In your RegisterActivity you have to write this

@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {     Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);     fragment.onActivityResult(requestCode, resultCode, data); } 

and then you will receive result in your Fragment.

Hope it helps you.

Answers 3

Have you tried disabling ProGuard? Set minifyEnabled to false in your build.gradle and see if it helps, your configuration may be out of date or incorrect.

Also you can check if your device is runing 9.6.1+ version of Google Play services.

Read More

Saturday, October 1, 2016

How to close ACTION_USAGE_ACCESS_SETTINGS intent when user click correct target application?

Leave a Comment

I am using Intent ACTION_USAGE_ACCESS_SETTINGS in setting (Settings->Security->Apps with usage access) to use UsageStatsManager in the Lollipop version.

 public static final int MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS = 1;   if(!hasPermission()){                 startActivityForResult(                         new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS),                         MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS);             } 

First, onCreate() will check the permission for the app. and turn on the Intent if the app has no permission (does not check)

@TargetApi(Build.VERSION_CODES.LOLLIPOP) private boolean hasPermission() {     try {         PackageManager packageManager = getApplicationContext().getPackageManager();         ApplicationInfo applicationInfo = packageManager.getApplicationInfo(getApplicationContext().getPackageName(), 0);         AppOpsManager appOpsManager = (AppOpsManager) getApplicationContext().getSystemService(Context.APP_OPS_SERVICE);         int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);         return (mode == AppOpsManager.MODE_ALLOWED);      } catch (PackageManager.NameNotFoundException e) {         return false;     } } 

My question is that I want to close the setting window, if the user chooses (check) in target app, otherwise, it will show a message about application name to guide the chosen of the user. How can I do it? Thank you. I think it will do in onActivityResult function

@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {     if (requestCode == MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS){         ...     } } 

I refer the link Check if my application has usage access enabled, but it just checks enable of the app.

1 Answers

Answers 1

AppOpsManager has another interesting method:

[void startWatchingMode (String op, String packageName, AppOpsManager.OnOpChangedListener callback)](https://developer.android.com/reference/android/app/AppOpsManager.html#startWatchingMode(java.lang.String, java.lang.String, android.app.AppOpsManager.OnOpChangedListener))

from documentation:

Monitor for changes to the operating mode for the given op in the given app package.

Basically this is what you expect -> react on permission to read package usage stats switch change.

What you need to do is check the allowance state and if it is not granted, open the Settings and create a listener:

private boolean hasPermissionToReadNetworkHistory() {     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {         return true;     }     final AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);     int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,             android.os.Process.myUid(), getPackageName());     if (mode == AppOpsManager.MODE_ALLOWED) {         return true;     }     appOps.startWatchingMode(AppOpsManager.OPSTR_GET_USAGE_STATS,             getApplicationContext().getPackageName(),             new AppOpsManager.OnOpChangedListener() {                 @Override                 @TargetApi(Build.VERSION_CODES.KITKAT)                 public void onOpChanged(String op, String packageName) {                     int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,                             android.os.Process.myUid(), getPackageName());                     if (mode != AppOpsManager.MODE_ALLOWED) {                         return;                     }                     appOps.stopWatchingMode(this);                     Intent intent = new Intent(MainActivity.this, MainActivity.class);                     intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);                     getApplicationContext().startActivity(intent);                 }             });     requestReadNetworkHistoryAccess();     return false; }  private void requestReadNetworkHistoryAccess() {     Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);     startActivity(intent); } 

Be careful and remove the listener calling the method:

void stopWatchingMode (AppOpsManager.OnOpChangedListener callback)

The example above is just opening main application activity. However you might add any behaviour:

  • pass extra intent parameter to inform just opened activity to show dialog to user
  • Start background service to show toast, that user must grant the permission.
  • etc...

Check out this repository, as it demonstrates this case and the overall usage of NetworkStats.

Read More

Friday, September 23, 2016

Share Score on Facebook android

Leave a Comment

I want to share my game score on facebook. I checked lots of links and every post people are saying that POSTING on facebook using INTENT is not possible.If we are using intent than we can share only link.

If we have to share something on facebook than we have to use FaceBook SDK.

I have another doubt that all questions and answers were posted before Year 2014. Is any new thing come after year 2014.

My actual question is that, Is it possible to share score on Facebook using Intent or i have to use Facebook SDK ?

below is the intent code which i used for my application which is not working ......

        Intent intent = new Intent(Intent.ACTION_SEND);         intent.setType("text/plain");         intent.putExtra(Intent.EXTRA_TEXT, message);         startActivity(Intent.createChooser(intent, "Share on")); 

and below is the FacebookSDK code ...and Problem in this it is not showing score on the Post only link image is showing, and title & description is missing.

  FacebookSdk.sdkInitialize(getApplicationContext());              shareDialog = new ShareDialog(this);              if (ShareDialog.canShow(ShareLinkContent.class)) {                         linkContent = new ShareLinkContent.Builder()                                 .setContentTitle(title)                                 .setContentDescription(description)                                 .setContentUrl(Uri.parse(link)).                                 .setImageUrl(Uri.parse(imageLink)                                    .build();                          shareDialog.show(linkContent);                     } 

I used ShareDialog because

The Share dialog switches to the native Facebook for Android app, then returns control to your app after a post is published. If the Facebook app is not installed it will automatically fallback to the web-based dialog.

Below is the output ..........

output

@pravin this is error coming after your share API use

o

@Pravin this is my code of your share answer........

@Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         FacebookSdk.sdkInitialize(getApplicationContext());         callbackManager = CallbackManager.Factory.create();          setContentView(R.layout.activity_facebook);          Button mShare= (Button) findViewById(R.id.share);          mShare.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View v) {                  ShareOpenGraphObject object = new ShareOpenGraphObject.Builder()                         .putString("og:type", "game.achievement")                         .putString("og:title", "Name of your game")                         .putString("og:description", "description. You can share your score here")                         .putString("game:points", "445")                         .build();                  ShareOpenGraphAction action = new ShareOpenGraphAction.Builder()                         .setActionType("games.achieves")                         .putObject("game", object)                         .build();                     if (ShareDialog.canShow(ShareLinkContent.class)) {                     ShareOpenGraphContent content = new ShareOpenGraphContent.Builder()                             .setPreviewPropertyName("game")                             .setAction(action)                             .build();                      ShareDialog.show(Facebook.this, content);                 }             }         });         shareDialog = new ShareDialog(this);      } 

Thanx in advance ................

6 Answers

Answers 1

After long searching i found this as work for me in my Project till the actual answer will come ..........

            FacebookSdk.sdkInitialize(getApplicationContext());              shareDialog = new ShareDialog(this);             if (ShareDialog.canShow(ShareLinkContent.class)) {                     linkContent = new ShareLinkContent.Builder()                         .setQuote("Hi Guys I have completed Game 30 in 19 seconds  in this game")                         .setImageUrl(Uri.parse("https://lh3.googleusercontent.com/jUej7mN6M6iulmuwmW6Mk28PrzXgl-Ebn-MpTmkmwtOfj5f0hvnuw8j0NEzK0GuKoDE=w300-rw"))                         .setContentUrl(Uri.parse("https://play.google.com/store/apps/details?id=com.mobtraffiq.numbertap&hl=en"))                         .build();                      shareDialog.show(linkContent);                 } 

NOTE:-In this code its shared a quota. If any one get other answer please post with output.

Output:-

output

Please post guys if you get the actual answer of this question ....

Thank you for all the user who make their effort .......

I have learn many thing due to your answers .......

enjoy coding .........

Answers 2

Scores API

If you just want to share score you can use Scores API(Read Create or Update a Player's Score section). There is very less and unclear information in provided link so below code snippet might work for you.

    Bundle param = new Bundle();     param.putInt("score", 100);      new GraphRequest(     your_access_token,     "/USER_ID/scores",     param,     HttpMethod.POST,     new GraphRequest.Callback() {         public void onCompleted(GraphResponse response) {             /* handle the result */         }     } ).executeAsync(); 

Achievements API

Use Achievements API if you want to publish achievements in your game and reward players with scores for completing those achievements.You have to use Open Graph Stories to publish your game achievements on Facebook. Before publishing stories on behalf of people, You will have to submit them for review. Read this link for more information.There are two ways to publish an Open Graph story:

  1. Using the Share dialog
  2. Using your own custom interface

As you are using share dialog, I am going to throw some light on how to post game score using share dialog.

  1. Create an object with the object type game.achievement and set the properties on that object.
ShareOpenGraphObject object = new ShareOpenGraphObject.Builder()         .putString("og:type", "game.achievement")         .putString("title", "Title of the achievement type.")         .putString("og:description", "description. You can share your score here")         .putInt("game:points", Points in integer)   .putString("og:url", "url of achievement type")    .putString("og:image", "image url")    .putString("fb:app_id", "The App ID that owns this achievement type")    .build(); 

In above code snippet key is Object Properties and game.achievement is Object Type. Here is documentation for game:points.

  1. Then create an action and link the object to the action.
ShareOpenGraphAction action = new ShareOpenGraphAction.Builder()     .setActionType("games.achieves")     .putObject("game", object)     .build(); 

You can find different ActionTypes here.

  1. Finally, create the content model to represent the Open Graph story.
ShareOpenGraphContent content = new ShareOpenGraphContent.Builder()     .setPreviewPropertyName("game")     .setAction(action)     .build(); 

All objects and action types in your code must be lowercase. All property names require namespaces.

  1. Present the Share dialog by using the show method on ShareDialog.

ShareDialog.show(activityOrFragment, content);

Summary:-

The Scores API and Achievements API make it easy to build social leaderboards, persist player scores and award achievements to players in a social and cross-platform format. With the Scores API, you can store and reset a player's high-score and pull back a list of their friends' scores to populate a leaderboard. With the Achievements API, you can define a list of custom achievements that players can complete in your game, along with a score value that can be earned with each achievement.

Note:-

Both the Scores API and Achievements API are only available for apps that are categorized as Games.

Because these API let developers write information about player game state to the Graph API, they both require publish_actions permissions, which is subject to Login Review. To retrieve Score and Achievement information about a player's friends, both the player and their friends need to grant the user_friends permission.

Hope this will provide you and other users enough information on game integration with Facebook.

Answers 3

Just try the below snippet,

call wherever you want like below

ShareDialog shareDialog; FacebookSdk.sdkInitialize(mContext); shareDialog = new ShareDialog(mContext);  shareScoreonFB("345"); // just pass your score here in string format. call this inside click listener.  // GLOBAL FUNCTION TO SHARE SCORE ON FB  void shareScoreonFB(String score) { ShareLinkContent linkContent = new ShareLinkContent.Builder()                     .setContentTitle("Your score is : "+score)                     .setContentDescription("Any description that you needed")                     .setContentUrl(Uri.parse("https://play.google.com/store/apps/details?id=com.mobtraffiq.numbertap&hl=en")).build();             shareDialog.show(linkContent); } 

NOTE: Make sure you initialize the Facebook SDK.

Hope this helps you, let me know for queries.

Answers 4

I believe that the Facebook SDK uses a background Activity for the actual data transfer, but you still need to make your own activity, its layout, and the examples on here show you how to create your own Sharing and Login tools

Answers 5

You have to use Facebook SDK to do this, I think the main reason is about security.

This is a simple snippet for photo sharing example (not related to your question but i think you know you can't not do it by using Intent):

private void shareImage() {         SharePhoto photo = new SharePhoto.Builder()                 .setBitmap(bmp)                 .setCaption("Simple puzzle")                 .build();          SharePhotoContent content = new SharePhotoContent.Builder()                 .addPhoto(photo)                 .build();          ShareApi.share(content, null);     } 

Answers 6

Well, there are 3 things you should do :
1) Categorize your app as Games on Facebook Developers
2) Use the Achievements API and Scores API
3) Facebook for Developers officially has an answer to your question. Please refer to the link https://developers.facebook.com/docs/games/services/scores-achievements

[ OPTIONAL ]


If you want to study about General Sharing from your app by users than this link Facebook SharingAddit might also help you in as General Sharing of content from your app

Read More

Tuesday, March 15, 2016

Extract / distinguish ActivityAlias name from TargetActivity

Leave a Comment

I have multiple ActivityAliases which all start one single TargetActivity. Inside of my TargetActivity I try to distinguish the alias that started the TargetActivity.

The aliases are defined in Manifest as launchables (intent-filter), which will be displayed as shortcuts on the homescreen. The user will click on the shortcut and android will start the activity, which I defined in the "android:targetActivity=.." tag.

For that I currently extract the componentName from the Intent, which is given to my TargetActivity and using the className().

Like:

String aliasName = targetActivity.getComponentName().getClassName(); 

This works fine for a lot of devices. But currently I see some failures on the OnePlus. At that device, my technique only returns the className of my TargetActivity and therefore I can't deliver the action, based on the alias that the user started.

Are there any other, reliable methods to get ActivityAlias that was used to start the TargetActivity? It does not need to be the name itself, as long as I can distinguish them. I do not want to create dedicated TargetActivities for every Alias!

Thanks!

Ps.: I saw another way, which uses the PackageManager to retrieve the activityInfo and using the Activity.name. But I doubt that this will return something different than my first approach.

ActivityInfo aInfo = activity.getPackageManager().getActivityInfo(activity.getComponentName(), PackageManager.GET_META_DATA);  String aliasName = aInfo.name; 

I also tried meta-data:

Edit:

Unfortunately this method does not work for all devices. If the parsed alias-className from the activity.component returns the target-activity, then the meta-data approach fails, too.

I continued searching for an answer and found a good workaround to distinguish between my aliases inside of the TargetActivty.

You can provide meta-data within your ActivityAlias tag like so:

<activity-alias      android:name=".aliasName"      android:enabled="false"      android:exported="true"      android:icon="@drawable/someIconRes"      android:label="@string/someLabelRes" android:targetActivity=".yourTargetActivity">      <meta-data android:name="alias" android:value="valueToDistinguish"/>     <intent-filter>           <action android:name="android.intent.action.MAIN"/>          <category android:name="android.intent.category.LAUNCHER"/>      </intent-filter>  </activity-alias> 

The important part here is:

<meta-data android:name="alias" android:value="valueToDistinguish"/> 

Which is within the <activity-alias> here </activity-alias> tag.

To extract the meta-data you can get an ActivityInfo from the PackageManager with the TargetActivity:

ActivityInfo appInfo = activity.getPackageManager().getActivityInfo(activity.getComponentName(), PackageManager.GET_META_DATA); 

And extract the meta-data via:

    private static String getAliasNameByMetaData(ActivityInfo app) {     String aliasName = "";     if (app.metaData != null && app.metaData.containsKey(ALIAS_META_DATA_KEY)) {         aliasName = app.metaData.getString(ALIAS_META_DATA_KEY, "");     } else {         LOG.i("AliasName by META-DATA didn't work!");     }     LOG.v("AliasName by META-DATA: " + aliasName);     return aliasName; } 

Edit:

Inspecting the Activity class using the debugger, it includes a mActivityInfo field that is different from the ActivityInfo returned by getPackageManager().getActivityInfo() so you can extract it using reflection and check it's name.

Note: It seems that the ActivityInfo returned by getPackageManager().getActivityInfo() is a shallow copy of the mActivityInfo from the Activity. So, maybe this method does not resolve the issue:

Field field = Activity.class.getDeclaredField("mActivityInfo"); field.setAccessible(true); ActivityInfo value = (ActivityInfo) field.get(this); Log.e("APPINFO2", "NAME: " + value.name); 

0 Answers

Read More