Search This Blog

Friday, December 23, 2016

Google internet of thing plateform for android named "Android Things and Weave"

Google has announced a new platform to work with Android IoT applications to smartly connected devices.
For more update please refer

Announcing updates to Google’s Internet of Things platform: Android Things and Weave



To get started, check out Google's IoT developer site, or go directly to the Android Things, Weave, and Google Cloud Platform sites for documentation and code samples. You can also join Google's IoT Developers Community on Google+ to get the latest updates and share and discuss ideas with other developers.

Friday, October 14, 2016

Pick images from default gallery intent

Pick image from default gallery images... from android


final PackageManager packageManager = getPackageManager();
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

List<ResolveInfo> list = packageManager.queryIntentActivities(intent,
                                                      PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() > 0) {
         startActivityForResult(intent, PICK_IMAGE_REQUEST);
} else {
          Toast.makeText(UserProfileEditActivity.this, "No app can perform this action",                        Toast.LENGTH_LONG).show();
           return;
}

Sunday, September 25, 2016

Checking multiple run time permission for marshmellow and above in android

Hello friend., Here i am posting tutorial for granting multiple permission with common code.. You need to add this code once and check permission run time.

Make one class in with common methods can be added in it. I call it CM as common methods. Add the following code in the common code.


CM.java

public static void showMessageOKCancel(Activity context, String message,                                                                                                              DialogInterface.OnClickListener okListener) {
           new AlertDialog.Builder(context)
                           .setMessage(message)
                           .setPositiveButton("OK", okListener)
                           .setNegativeButton("Cancel", null)
                           .create()
                           .show();
}

public static void applyMarshmallowPermission(
                          final Activity context, String Permission[], String[] strPermissionMessage, 
                          final int RequestCode, OnPermissionAlreadyGrant callBackPermission) {
            final List<String> permissionsList = new ArrayList<String>();
            List<String> permissionsNeeded = new ArrayList<String>();

             for (int i = 0; i < Permission.length; i++) {
                         if (!addPermission(context, permissionsList, Permission[i])) {
                                            permissionsNeeded.add(strPermissionMessage[i]);
                         }
             }

             if (permissionsList.size() > 0) {
                         if (permissionsNeeded.size() > 0) {
                              // Need Rationale
                              String message = "You need to grant access to " + permissionsNeeded.get(0);
                              for (int i = 1; i < permissionsNeeded.size(); i++)
                                       message = message + ", " + permissionsNeeded.get(i);

                              showMessageOKCancel(context, message,
                                          new DialogInterface.OnClickListener() {
                                                  @Override
                                                   public void onClick(DialogInterface dialog, int which) {
                                                                  ActivityCompat.requestPermissions(context,                                                                                                     permissionsList.toArray(new                                                                                                                              String[permissionsList.size()]), RequestCode);
                                                   }
                                           });
                                  return;
                            }
                           ActivityCompat.requestPermissions(context, permissionsList.toArray(new                                                            String[permissionsList.size()]),  RequestCode);
                          return;
              }

               if (callBackPermission != null) {
                          callBackPermission.onPermssionAlreadyGranted();
                          return;
              }


}


private static boolean addPermission(Activity context, 
                                             List<String> permissionsList, String permission) {
                   
                            if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                                          permissionsList.add(permission);
                                          // Check for Rationale Option
                                          if (ActivityCompat.shouldShowRequestPermissionRationale(context, permission)) {
                                                            return false;
                                          }

                             }
       return true;

}

public static int checkNeverAskAgainList(Activity
                                                                context, String[] permissionsList) {
          int deniedList = 0;
          for (String strPermission : permissionsList) {
                   boolean isRational = ActivityCompat.shouldShowRequestPermissionRationale(context, strPermission);
                   if (isRational) {
                              deniedList++;
                   }
           }
   return deniedList;
}


public static void goToSettings(Activity context) {
                Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + context.getPackageName()));
                myAppSettings.addCategory(Intent.CATEGORY_DEFAULT);
                myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(myAppSettings);
}


This methods are used to check for permissions that user has to allow or user will go to setting and allow the permission that our app needs.

Now how to use this for multiple permission grant in your activity using this methods.

Add this in your activity when you need to check the permissions

//Mention list of permissions that are needed in your activity
String strPermissoinList[] = new String[]{android.Manifest.permission.READ_PHONE_STATE,                                                      android.Manifest.permission.GET_ACCOUNTS};
// Description to be shown to user for particular permission if user denied once.
String strPermissionMessage[] = new String[]{"Phone State", "Google+ Account"};
// Request code to be used when permission is received from user
public static final int PERMISSION_MULTIPLE_GRANT_CODE = 1001;



public void buttonClick(View view) {
               CM.applyMarshmallowPermission(MainActivity.this, strPermissoinList,                                                          strPermissionMessage,                                                                                                           PERMISSION_MULTIPLE_GRANT_CODE, 
                                                new OnPermissionAlreadyGrant() { 
                   @Override
                   public void onPermssionAlreadyGranted() {
                              // if you have already granted or sdk version is below marshmellow
                              Toast.makeText(MainActivity.this, "You have allowed all permission.                                                                applyMarshmallowPermission : " +                                                                                      CM.getDeviceId(MainActivity.this),                                                                                        Toast.LENGTH_SHORT).show();
                  }
          });
}

Now add the following lines in the onRequestPermissionsResult code.

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
       switch (requestCode) {
             case PERMISSION_MULTIPLE_GRANT_CODE:

                    Map<String, Integer> perms = new HashMap<String, Integer>();
                    // Initial
                    perms.put(android.Manifest.permission.READ_PHONE_STATE, PackageManager.PERMISSION_GRANTED);
                    perms.put(android.Manifest.permission.GET_ACCOUNTS, PackageManager.PERMISSION_GRANTED);
                    // Fill with results
                    for (int i = 0; i < permissions.length; i++)
                            perms.put(permissions[i], grantResults[i]);
                      // Check for READ_PHONE_STATE
                      if (perms.get(android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED
                                       && perms.get(android.Manifest.permission.GET_ACCOUNTS) == PackageManager.PERMISSION_GRANTED) {
                                          Toast.makeText(this, "You have allowed all permission. onRequestPermissionsResult :: " + CM.getDeviceId(MainActivity.this), Toast.LENGTH_SHORT)
.show();

                       } else {

                           int countBlock = CM.checkNeverAskAgainList(this, strPermissoinList);
                           if (countBlock > 0) {
                                  // Permission Denied
                                   Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT)
.show();
                            } else {
                                    CM.showMessageOKCancel(MainActivity.this, "Go to setting and give permission",
                                                                            new DialogInterface.OnClickListener() {
                                   @Override
                                   public void onClick(DialogInterface dialog, int which) {
                                                  CM.goToSettings(MainActivity.this);
                                   }
                             });
                    }
              }
              break;
          default:
               super.onRequestPermissionsResult(requestCode, permissions, grantResults);
       }
}

Finally the callback interface that you need to define in your code is below

public interface OnPermissionAlreadyGrant {
           void onPermssionAlreadyGranted();
}

file:// scheme is now not allowed to be attached with Intent on targetSdkVersion 24 (Android Nougat). What todo?

https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-android-nougat/en

Android Nougat is almost be publicly released. And as an Android developer, we need to prepare ourself to adjust targetSdkVersion to the latest one, 24, to let everything works perfectly on the newest release of Android.

And as always, everytime we adjust targetSdkVersion, we need to check and make sure that every single part of our code works perfectly fine. If you just simply change the number, I could say that your application is taking a high risk of crashing or malfunction. In this case, when you change your app's targetSdkVersion to 24, we need to check that every single function works flawlessly on Android Nougat (24).

And this is one of the checklist you need to mark done before releasing your new version. There is one big security change on Android N like quoted below:


Passing file:// URIs outside the package domain may leave the receiver with an unaccessible path. Therefore, attempts to pass a file:// URI trigger a FileUriExposedException. The recommended way to share the content of a private file is using the FileProvider



Summarily, file:// is not allowed to attach with Intent anymore or it will throw FileUriExposedException which may cause your app crash immediately called.

This blog will talk about this issue and also about the solution how to make it work on Android N.


Real example with a crashing problem

You may be curious which situation that can really cause the problem. So to make it be easy to you all, let me show you a real usage example that causes crashing. The easiest example is the way we take a photo through Intent with ACTION_IMAGE_CAPTURE type. Previously we just pass the target file path with file:// format as an Intent extra which works fine on Android Pre-N but will just simply crash on Android N and above.

If you are running the code with targetsdkversion set to 23. But this will give you an following exception when you set targetsdkversion to 24.

FATAL EXCEPTION: main Process: com.inthecheesefactory.lab.intent_fileprovider, PID: 28905 
android.os.FileUriExposedException: file:///storage/emulated/0/DCIM/Camera/IMG_25092016.jpg exposed beyond app through ClipData.Item.getUri() 
at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799) 
at android.net.Uri.checkFileUriExposed(Uri.java:2346) 
at android.content.ClipData.prepareToLeaveProcess(ClipData.java:832) ...

The reason is quite obvious. file:// is not allowed as an attached URI in Intent or FileUriExposedException would be thrown.

And this is a big issue that you have to make sure that all code related to this case has already been fixed before releasing a new version with targetSdkVersion 24 or your app may crash on some of your user's device.


Why nougat does not allow passing file:// with intent any more?

You may be curious why Android team decide to change this behavior. Actually there is a good reason behind.

If file path is sent to the target application (Camera app in this case), file will be fully accessed through the Camera app's process not the sender one.



But let's consider thoroughly, actually Camera is launched by our application to take a photo and save as a file on our app's behalf. So the access right to that file should be our app's not Camera's. Every operation did with the file should be done through our application not by Camera app itself.

And that's why file:// is now prohibited on targetSdkVersion 24 to force every developer to do this task in the proper way.




Solution is as below :

So if file:// is not allowed anymore, which approach should we go for? The answer is we should send the URI through content:// scheme instead which is the URI scheme for Content Provider. In this case, we would like to share an access to a file through our app so FileProvider is needed to be implemented. Flow is now changed like below:





And now, with FileProvider, file operation would be done through our app process like it supposes to be !

It is quite easy to implement FileProvider on your application. First you need to add a FileProvider<provider> tag in AndroidManifest.xml under <application> tag like below:



AndroidMenifest.xml

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          ........
          <application 

                      ...
                     <provider
                               android:name="android.support.v4.content.FileProvider"

                               android:authorities="${applicationId}.provider"
                               android:exported="false"
                               android:grantUriPermissions="true">
                               <meta-data android:name="android.support.FILE_PROVIDER_PATHS"                                                                 android:resource="@xml/provider_paths"/>
                      </provider>
            </application>
</manifest>


And then create a provider_paths.xml file in xml folder under res folder. Folder may be needed to create if it doesn't exist.

The content of the file is shown below. It describes that we would like to share access to the External Storage at root folder (path=".") with the name external_files.


res/xml/provider_paths.xml

<?xml version="1.0" encoding="utf-8"?> 
           <paths xmlns:android="http://schemas.android.com/apk/res/android">
           <external-path name="external_files" path="."/> 
</paths>

FileProvider is now declared and be ready to use.

The last step is to change the line of code below in Activity



Uri photoURI = Uri.fromFile(createImageFile());

to

Uri photoURI = FileProvider.getUriForFile(MainActivity.this,
               BuildConfig.APPLICATION_ID +
               ".provider", createImageFile());



You are done, Your code should run in all the previous version with nougat.

Firebase notification if you are creating a new one

Add firebase to your application


To add Firebase to your app you'll need a Firebase project and a Firebase configuration file for your app.
  1. Create a Firebase project in the Firebase console, if you don't already have one. If you already have an existing Google project associated with your mobile app, click Import Google Project. Otherwise, click Create New Project.
  2. Click Add Firebase to your Android app and follow the setup steps. If you're importing an existing Google project, this may happen automatically and you can just download the config file.
  3. When prompted, enter your app's package name. It's important to enter the package name your app is using; this can only be set when you add an app to your Firebase project.
  4. At the end, you'll download a google-services.json file. You can download this file again at any time.
  5. If you haven't done so already, copy this into your project's module folder, typically app/.

* Note: If you have multiple build variants with different package names defined, each app must be added to your project in Firebase console.


Add the SDK
If you would like to integrate the Firebase libraries into one of your own projects, you need to perform a few basic tasks to prepare your Android Studio project. You may have already done this as part of adding Firebase to your app.
First, add rules to your root-level build.gradle file, to include the google-services plugin: 
  buildscript {
        //....
        dependencies {
            //.....
            classpath 'com.google.gms:google-services:3.0.0'
             }
}


Then, in your module Gradle file (usually the app/build.gradle), add the apply plugin line at the bottom of the file to enable the Gradle plugin:


apply plugin: 'com.android.application'

android{
        //....
}

dependencies {
    // ...
    compile 'com.google.firebase:firebase-core:9.6.0'
}

// ADD THIS AT THE BOTTOM
apply plugin  : 'com.google.gms.google-services'


Set Up a Firebase Cloud Messaging Client App on Android

FCM clients require devices running Android 2.3 or higher that also have the Google Play Store app installed, or an emulator running Android 2.3 with Google APIs. Note that you are not limited to deploying your Android apps through Google Play Store.

Edit your app manifest

Add the following to your app's manifest:
  • A service that extends FirebaseMessagingService. This is required if you want to do any message handling beyond receiving notifications on apps in the background. To receive notifications in foregrounded apps, to receive data payload, to send upstream messages, and so on, you must extend this service.
  • A service that extends FirebaseInstanceIdService to handle the creation, rotation, and updating of registration tokens. This is required for sending to specific devices or for creating device groups.
  • If FCM is critical to the Android app's function, be sure to set android:minSdkVersion="8" or higher in the manifest. This ensures that the Android app cannot be installed in an environment in which it could not run properly.

<service
   
android:name=".MyFirebaseMessagingService">
   
<intent-filter>
       
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
   
</intent-filter>
</service>



<service
   
android:name=".MyFirebaseInstanceIDService">
   
<intent-filter>
       
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
   
</intent-filter>

</service>


Check this for implementing these 2 services




Sunday, September 18, 2016

Migrate a GCM Client App for Android to Firebase Cloud Messaging

Import your GCM project as a Firebase project


  1. In the Firebase console, select Import Google Project.
  2. Select your GCM project from the list of existing projects and select Add Firebase.
  3. In the Firebase welcome screen, select Add Firebase to your Android App.
  4. Provide your package name and SHA-1, and select Add App. A new google-services.json file for your Firebase app is downloaded.
  5. Select Continue and follow the detailed instructions for adding the Google Services plugin in Android Studio.

Switch to FCM in the app-level build.gradle

BEFORE
dependencies {
  compile "com.google.android.gms:play-services-gcm:8.4.0"
}
AFTER
dependencies {
  compile "com.google.firebase:firebase-messaging:9.0.0"
}

Remove the permissions required by GCM

All the permissions required by FCM are now added automatically by library

BEFORE

<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission android:name="<your-package-name>.permission.C2D_MESSAGE"
            android:protectionLevel="signature" />
<uses-permission android:name="<your-package-name>.permission.C2D_MESSAGE" />

AFTER

No permissions


Remove the receiver from the app manifest
With FCM, com.google.android.gms.gcm.GcmReceiver is added automatically.
AndroidManifest.xml Before
<receiver
    android:name="com.google.android.gms.gcm.GcmReceiver"
    android:exported="true"
    android:permission="com.google.android.c2dm.permission.SEND" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <category android:name="com.example.gcm" />
    </intent-filter>
</receiver>

AndroidManifest.xml After

No receiver


Migrate your listener service

A service extending InstanceIDListenerService is now required only if you want to access 
the FCM token.

This is needed if you want to
  • Manage device tokens to send a messages to single device directly, or
  • Send messages to device group, or
  • Subscribe devices to topics with the server subscription management API.
If you don't use these features, you can completely remove this service along with client code to initiate the generation of a registration token.

Update the Android Manifest

AndroidManifest.xml Before
<service
    android:name=".MyInstanceIDListenerService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.android.gms.iid.InstanceID" />
    </intent-filter>
</service>
AndroidManifest.xml After

<service
   android:name=".MyInstanceIDListenerService">
   <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
   </intent-filter>
</service>

Update your InstanceIDListenerService

Change MyInstanceIDListenerService to extend FirebaseInstanceIdService, and update code to listen for token updates and get the token whenever a new token is generated. MyInstanceIDListenerService.java Before public class MyInstanceIDListenerService extends InstanceIDListenerService { @Override public void onTokenRefresh() { // Fetch updated Instance ID token and notify our app's server of any changes (if applicable). Intent intent = new Intent(this, RegistrationIntentService.class); startService(intent); } } MyInstanceIDListenerService.java After

public class MyInstanceIDListenerService extends FirebaseInstanceIdService {
  /**
   * Called if InstanceID token is updated. This may occur if the security of
   * the previous token had been compromised. Note that this is also called
   * when the InstanceID token is initially generated, so this is where
   * you retrieve the token.
   */
  
   // [START refresh_token]
  
   @Override
   public void onTokenRefresh() {
   // Get updated InstanceID token.
   String refreshedToken = FirebaseInstanceId.getInstance().getToken();
   Log.d(TAG, "Refreshed token: " + refreshedToken);
   // TODO: Implement this method to send any registration to your app's servers.
   sendRegistrationToServer(refreshedToken);
  }
}
Remove registration

You no longer need to explicitly initiate the generation of a registration token — the library does this automatically. Therefore, you can remove code like the following:
  InstanceID instanceID = InstanceID.getInstance(this);
  String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
          GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
  // [END get_token]
  Log.i(TAG, "GCM Registration Token: " + token);
Migrate your GcmListenerService

A service extending GcmListenerService is now required only for the following use cases:
  • receiving messages with notification payload while the application is in foreground
  • receiving messages with data payload only
  • receiving errors in case of upstream message failures.
If you don't use these features, and you only care about displaying notifications messages when the app is not in the foreground, you can completely remove this service.

Update the Android Manifest

AndroidManifest.xml Before


<service
    android:name=".MyGcmListenerService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
    </intent-filter>
</service>

AndroidManifest.xml After

<service
    android:name=".MyFcmListenerService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

Update your GcmListenerService

Change MyGcmListenerService to extend FirebaseMessagingService and update the signature of the method onMessageReceived(). This example updates the service name to MyFcmListenerService.

MyGcmListenerService.java Before

public class MyGcmListenerService extends GcmListenerService {
  @Override
  public void onMessageReceived(String from, Bundle data){
    ...
  }
}

MyFcmListenerService.java after

public class MyFcmListenerService extends FirebaseMessagingService {
   @Override
   public void onMessageReceived(RemoteMessage message){ 
      String from = message.getFrom();
       Map data = message.getData();
  }
}

Firebase has three message types:

Notification messages : Notification message works on background or foreground. When app is in background, Notification messages are delivered to the system tray. If the app is in the foreground, messages are handled by onMessageReceived() or didReceiveRemoteNotification callbacks. These are essentially what is referred to as Display messages.

Data messages: On Android platform, data message can work on background and foreground. The data message will be handled by onMessageReceived(). A platform specific note here would be: On Android, the data payload can be retrieved in the Intent used to launch your activity. To elaborate, if you have "click_action":"launch_Activity_1", you can retrieve this intent through getIntent() from only Activity_1.

Messages with both notification and data payloads: When in the background, apps receive the notification payload in the notification tray, and only handle the data payload when the user taps on the notification. When in the foreground, your app receives a message object with both payloads available. Secondly, the click_action parameter is often used in notification payload and not in data payload. If used inside data payload, this parameter would be treated as custom key-value pair and therefore you would need to implement custom logic for it to work as intended.