Pages

Wednesday 14 December 2016

file:// scheme is now not allowed to be attached with Intent on targetSdkVersion 24

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.
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 (MediaStore.EXTRA_OUTPUT) which works fine on Android Pre-N but will just simply crash on Android N and above.

Why Nougat does not allow passing file:// with Intent anymore?

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

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:

 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:
AndroidManifest.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>
Done! FileProvider is now declared and be ready to use.
The final step is to change the line of code below in MainActivity.java
Uri photoURI = Uri.fromFile(createImageFile());
to
Uri photoURI = FileProvider.getUriForFile(MainActivity.this,
        BuildConfig.APPLICATION_ID + ".provider",
        createImageFile());
And .... done ! Your application should now work perfectly fine on any Android version including Android Nougat. Yah !

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

Tuesday 12 April 2016

Git Rebase example

Following tutorial will show how to do git rebase.
This tutorial explain what is rebase first and then it will give demo steps of rebasing.

Explanation of rebase
Reference : https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase

git rebase

Rebasing is the process of moving a branch to a new base commit. The general process can be visualized as the following:
Git Tutorial: Rebase to maintain a linear project history.
From a content perspective, rebasing really is just moving a branch from one commit to another. But internally, Git accomplishes this by creating new commits and applying them to the specified base—it’s literally rewriting your project history. It’s very important to understand that, even though the branch looks the same, it’s composed of entirely new commits.

Usage

git rebase <base>
Rebase the current branch onto <base>, which can be any kind of commit reference (an ID, a branch name, a tag, or a relative reference to HEAD).

Discussion

The primary reason for rebasing is to maintain a linear project history. For example, consider a situation where the master branch has progressed since you started working on a feature:
Git Rebase Branch onto Master
You have two options for integrating your feature into the masterbranch: merging directly or rebasing and then merging. The former option results in a 3-way merge and a merge commit, while the latter results in a fast-forward merge and a perfectly linear history. The following diagram demonstrates how rebasing onto master facilitates a fast-forward merge.
Git Tutorial: Fast-forward merge
Rebasing is a common way to integrate upstream changes into your local repository. Pulling in upstream changes with git merge results in a superfluous merge commit every time you want to see how the project has progressed. On the other hand, rebasing is like saying, “I want to base my changes on what everybody has already done.”

Don’t Rebase Public History

As we’ve discussed with git commit --amend and git reset, you should never rebase commits that have been pushed to a public repository. The rebase would replace the old commits with new ones, and it would look like that part of your project history abruptly vanished.

Examples

The example below combines git rebase with git merge to maintain a linear project history. This is a quick and easy way to ensure that your merges will be fast-forwarded.
# Start a new feature
git checkout -b new-feature master
# Edit files
git commit -a -m "Start developing a feature"
In the middle of our feature, we realize there’s a security hole in our project
# Create a hotfix branch based off of master
git checkout -b hotfix master
# Edit files
git commit -a -m "Fix security hole"
# Merge back into master
git checkout master
git merge hotfix
git branch -d hotfix
After merging the hotfix into master, we have a forked project history. Instead of a plain git merge, we’ll integrate the feature branch with a rebase to maintain a linear history:
git checkout new-feature
git rebase master
This moves new-feature to the tip of master, which lets us do a standard fast-forward merge from master:
git checkout master
git merge new-feature

----------------------------------------------------------------------
Demo

Our purpose of demo

Lets say we have following branches.

master:
at first launch master branch have base setup of our project.

module1:
suppose developer 1 worked on module 1. and merge it with master. so master have base setup and module1

module2:
suppose developer 2 worked on module 2. and merge it with master. so master have base setup and module1 and module2



As a result when both developer complete work on module 1 and module 2 we want master branch have both module and module1 and module2 have it's change seperatly.
------------------------------
Steps to achieve it

Lets init git. in Windows open git-bash or in Linux open terminal

1 : cd <your demo folder path>
2 : git init : it will init git in above given folder
3 : In master branch : let's create file named "base-setup.txt" and commit it by these commands. git add -A, git commit -m "base setup in master"
4 : Checkout new branch module1 and add some module 1 file or modify required file and commit changes of module1 branch. we may need following commands.
    git checkout -B module1.
    after this do your work.
    when work completed then use following commands to commit changes in module1 branch.
    git add -A and git commit -m "module1 completed" commands

5 : Lets merge module 1 with master.
    git checkout master
    git rebase module1.
    now if there is conflict then open that file in editor and resolve conflict manually. and run git add -A to resolve that conflict.
    After resolve conflict run "git rebase --continue"
    Now you can check that master have its own files as well as module1's file.
6 : Now follow step 4 and 5 for module2 branch.
7 : After these you can see master have module1 and module2 changes. module1 have only its files. module2 also have only its file.

Conculation : We can use rebase for module management. We can also use this for version management i.e. version 1 have some feature, version 2 have some other feature while master have all feature.

Tuesday 2 February 2016

How to find proper aspect ratio

use following code to find aspect ration from source size and destination size.


private int[] getVideoSizeWithAspect(int srcWidth, int srcHeight, int destWidth, int destHeight) {
        int aspectWidthByDestWidth, aspectHeightByDestWidth;
        int aspectWidthByDestHeight, aspectHeightByDestHeight;

        /* aspect sizes related to width */
        aspectWidthByDestWidth = destWidth;
        aspectHeightByDestWidth = aspectWidthByDestWidth * srcHeight / srcWidth;

        /* aspect sizes related to height */
        aspectHeightByDestHeight = destHeight;
        aspectWidthByDestHeight = aspectHeightByDestHeight * srcWidth / srcHeight;

        if (aspectWidthByDestWidth > aspectWidthByDestHeight && aspectHeightByDestWidth <= destHeight) {
            int[] videoViewSize = new int[2];
            videoViewSize[0] = aspectWidthByDestWidth;
            videoViewSize[1] = aspectHeightByDestWidth;
            return videoViewSize;
        } else {
            int[] videoViewSize = new int[2];
            videoViewSize[0] = aspectWidthByDestHeight;
            videoViewSize[1] = aspectHeightByDestHeight;
            return videoViewSize;
        }
    }

Thursday 7 January 2016

getView called multiple times

First check this question in detail : http://stackoverflow.com/questions/11186004/yet-another-getview-called-multiple-times

 short explanation about listview.

Thumb rule : never use wrap_content for listview's height and width.

if we use height or width of listview as wrap_content then adapter's getview will call more then once for same item after notifydatasetchanged.

to overcome this situation as suggested in above link use listview's height and width as match_parent or fixed size.