Skip to content

Instantly share code, notes, and snippets.

@ankesh-kumar
Last active September 5, 2020 06:34
Show Gist options
  • Save ankesh-kumar/eb6ca42e4a263653f9136244f9db806f to your computer and use it in GitHub Desktop.
Save ankesh-kumar/eb6ca42e4a263653f9136244f9db806f to your computer and use it in GitHub Desktop.
webView_with_download_feature
import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.drawable.ColorDrawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.DownloadListener;
import android.webkit.JavascriptInterface;
import android.webkit.JsResult;
import android.webkit.MimeTypeMap;
import android.webkit.URLUtil;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.gun0912.tedpermission.PermissionListener;
import com.gun0912.tedpermission.TedPermission;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class MainActivity extends AppCompatActivity {
WebView wb;
private TransparentProgressDialog pDialog;
String weburl="";
public static final int INPUT_FILE_REQUEST_CODE = 1;
private ValueCallback<Uri[]> mFilePathCallback;
private String mCameraPhotoPath;
private static final String TAG = "AppView";
private boolean mbErrorOccured = false;
private boolean mbReloadPressed = false;
TextView tvError;
private long enqueue;
ProgressBar pBar;
private LinearLayout mlLayoutRequestError = null;
private Handler mhErrorLayoutHide = null;
ImageView btnRetry;
DownloadManager mdDownloadManager;
BroadcastReceiver receiver;
public static final int Request_Id_Multiple_Permissions=1;
String current_web_url="";
private FirebaseAnalytics mFirebaseAnalytics;
int result_code;
String web_url="";
@Override
public void onBackPressed() {
current_web_url= wb.getUrl().toLowerCase();
if(current_web_url.equalsIgnoreCase(web_url))
goExit();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webView_with_download_feature);
ImageView ic_back=findViewById(R.id.ic_back);
ic_back.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
goExit();
}
});
PermissionListener permissionlistener = new PermissionListener() {
@Override
public void onPermissionGranted() {
//Toast.makeText(MainActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
}
@Override
public void onPermissionDenied(List<String> deniedPermissions) {
Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();
}
};
TedPermission.with(this)
.setPermissionListener(permissionlistener)
.setDeniedMessage("If you reject permission, you can not use some services\n\nPlease turn on permissions at [Settings] > [Permission]")
.setPermissions(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.check();
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
btnRetry = findViewById(R.id.btnRetry);
btnRetry.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
retry();
}
});
pDialog = new TransparentProgressDialog(MainActivity.this);
mlLayoutRequestError = findViewById(R.id.lLayoutRequestError);
mhErrorLayoutHide = getErrorLayoutHideHandler();
tvError = findViewById(R.id.tvError);
weburl = getResources().getString(R.string.app_url);
wb = findViewById(R.id.webview);
if (!isNetworkConnected()) {
showErrorLayout();
} else {
wb.setWebViewClient(new MyBrowser());
wb.getSettings().setLoadsImagesAutomatically(true);
wb.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
wb.getSettings().setJavaScriptEnabled(true);
wb.getSettings().setDomStorageEnabled(true);
wb.getSettings().setSavePassword(true);
wb.addJavascriptInterface(new WebAppInterface(this), "Android");
wb.getSettings().setAllowFileAccess(true);
wb.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
WebChromeClient myWebChromeClient = new MyWebChromeClient();
wb.setWebChromeClient(myWebChromeClient);
wb.loadUrl(weburl);
wb.setDownloadListener(new DownloadListener() {
@Override
public void onDownloadStart(String url, String userAgent, String contentDescription,
String mimetype, long contentLength) {
/*
DownloadManager.Request
This class contains all the information necessary to request a new download.
The URI is the only required parameter. Note that the default download
destination is a shared volume where the system might delete your file
if it needs to reclaim space for system use. If this is a problem,
use a location on external storage (see setDestinationUri(Uri).
*/
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
/*
void allowScanningByMediaScanner ()
If the file to be downloaded is to be scanned by MediaScanner, this method
should be called before enqueue(Request) is called.
*/
request.allowScanningByMediaScanner();
/*
DownloadManager.Request setNotificationVisibility (int visibility)
Control whether a system notification is posted by the download manager
while this download is running or when it is completed. If enabled, the
download manager posts notifications about downloads through the system
NotificationManager. By default, a notification is shown only
when the download is in progress.
It can take the following values: VISIBILITY_HIDDEN, VISIBILITY_VISIBLE,
VISIBILITY_VISIBLE_NOTIFY_COMPLETED.
If set to VISIBILITY_HIDDEN, this requires the permission
android.permission.DOWNLOAD_WITHOUT_NOTIFICATION.
Parameters
visibility int : the visibility setting value
Returns
DownloadManager.Request this object
*/
request.setNotificationVisibility(
DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
/*
DownloadManager
The download manager is a system service that handles long-running HTTP
downloads. Clients may request that a URI be downloaded to a particular
destination file. The download manager will conduct the download in the
background, taking care of HTTP interactions and retrying downloads
after failures or across connectivity changes and system reboots.
*/
/*
String guessFileName (String url, String contentDisposition, String mimeType)
Guesses canonical filename that a download would have, using the URL
and contentDisposition. File extension, if not defined,
is added based on the mimetype
Parameters
url String : Url to the content
contentDisposition String : Content-Disposition HTTP header or null
mimeType String : Mime-type of the content or null
Returns
String : suggested filename
*/
String fileName = URLUtil.guessFileName(url,contentDescription,mimetype);
/*
DownloadManager.Request setDestinationInExternalPublicDir
(String dirType, String subPath)
Set the local destination for the downloaded file to a path within
the public external storage directory (as returned by
getExternalStoragePublicDirectory(String)).
The downloaded file is not scanned by MediaScanner. But it can be made
scannable by calling allowScanningByMediaScanner().
Parameters
dirType String : the directory type to pass to
getExternalStoragePublicDirectory(String)
subPath String : the path within the external directory, including
the destination filename
Returns
DownloadManager.Request this object
Throws
IllegalStateException : If the external storage directory cannot be
found or created.
*/
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,fileName);
DownloadManager dManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
/*
long enqueue (DownloadManager.Request request)
Enqueue a new download. The download will start automatically once the
download manager is ready to execute it and connectivity is available.
Parameters
request DownloadManager.Request : the parameters specifying this download
Returns
long : an ID for the download, unique across the system. This ID is used
to make future calls related to this download.
*/
dManager.enqueue(request);
}
});
pDialog = new TransparentProgressDialog(MainActivity.this);
pDialog.setCancelable(true);
pDialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
pDialog.show();
}
}
private boolean isNetworkConnected() {
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
}
//Class to be injected in Web page
public class WebAppInterface {
Context mContext;
/**
* Instantiate the interface and set the context
*/
WebAppInterface(Context c) {
mContext = c;
}
@JavascriptInterface
public void moveToNextScreen(String st) {
Toast.makeText(MainActivity.this,st,Toast.LENGTH_LONG).show();
}
}
public class JavaScriptInterface {
Context mContext;
/** Instantiate the interface and set the context */
JavaScriptInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_LONG).show();
}
}
private class MyBrowser extends WebViewClient {
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
mbErrorOccured = true;
showErrorLayout();
super.onReceivedError(view, errorCode, description, failingUrl);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
super.onPageStarted(view, url, favicon);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//view.loadUrl(url);
if(!isNetworkConnected()){
//Toast.makeText(MainActivity.this, "You are not Connected with Internet", Toast.LENGTH_LONG).show();
showErrorLayout();
}
else {
boolean value = true;
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) {
MimeTypeMap mime = MimeTypeMap.getSingleton();
String mimeType = mime.getMimeTypeFromExtension(extension);
if (mimeType != null) {
mdDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(
Uri.parse(url));
File destinationFile = new File(
Environment.getExternalStorageDirectory(),
getFileName(url));
request.setDescription("Downloading");
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
value = false;
enqueue = mdDownloadManager.enqueue(request);
registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
if (value) {
view.loadUrl(url);
}
}
}
return true;
}
/**
* File name from URL
*
* @param url
* @return
*/
public String getFileName(String url) {
String filenameWithoutExtension = "";
filenameWithoutExtension = System.currentTimeMillis()
+ "." + MimeTypeMap.getFileExtensionFromUrl(url);
return filenameWithoutExtension;
}
@Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
super.onPageFinished(view, url);
if(pDialog.isShowing())
pDialog.dismiss();
}
// To handle "Back" key press event for WebView to go back to previous screen.
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (wb.canGoBack()) {
wb.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
private void showAlert(){
AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this);
b.setTitle("Download Completed");
b.setPositiveButton("OK", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int whichButton)
{
}
});
b.create().show();
}
public class MyWebChromeClient extends WebChromeClient {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result)
{
final JsResult finalRes = result;
new AlertDialog.Builder(view.getContext())
.setMessage(message)
.setPositiveButton(android.R.string.ok,
new AlertDialog.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which) {
finalRes.confirm();
}
})
.setCancelable(false)
.create()
.show();
return true;
}
public boolean onShowFileChooser(
WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
if(mFilePathCallback != null) {
mFilePathCallback.onReceiveValue(null);
}
mFilePathCallback = filePathCallback;
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
} catch (IOException ex) {
// Error occurred while creating the File
Log.e(TAG, "Unable to create Image File", ex);
}
// Continue only if the File was successfully created
if (photoFile != null) {
mCameraPhotoPath = "file:" + photoFile.getAbsolutePath();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
} else {
takePictureIntent = null;
}
}
String[] mime_type={"application/pdf","image/*"};
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.setType("*/*");
contentSelectionIntent.putExtra(Intent.EXTRA_MIME_TYPES,mime_type);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
Intent[] intentArray;
if(takePictureIntent != null) {
intentArray = new Intent[]{takePictureIntent};
} else {
intentArray = new Intent[0];
}
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
//chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent_Image);
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);
return true;
}
}
/**
* More info this method can be found at
* http://developer.android.com/training/camera/photobasics.html
*
* @return
* @throws IOException
*/
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File imageFile = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
return imageFile;
}
/**
* Convenience method to set some generic defaults for a
* given WebView
*
* @param webView
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void setUpWebViewDefaults(WebView webView) {
WebSettings settings = webView.getSettings();
// Enable Javascript
settings.setJavaScriptEnabled(true);
// Use WideViewport and Zoom out if there is no viewport defined
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
// Enable pinch to zoom without the zoom buttons
settings.setBuiltInZoomControls(true);
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
// Hide the zoom controls for HONEYCOMB+
settings.setDisplayZoomControls(false);
}
// Enable remote debugging via chrome://inspect
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
// We set the WebViewClient to ensure links are consumed by the WebView rather
// than passed to a browser if it can
webView.setWebViewClient(new WebViewClient());
}
@Override
public void onActivityResult (int requestCode, int resultCode, Intent data) {
if(requestCode != INPUT_FILE_REQUEST_CODE || mFilePathCallback == null) {
super.onActivityResult(requestCode, resultCode, data);
return;
}
Uri[] results = null;
// Check that the response is a good one
if(resultCode == Activity.RESULT_OK) {
if(data == null) {
// If there is not data, then we may have taken a photo
if(mCameraPhotoPath != null) {
results = new Uri[]{Uri.parse(mCameraPhotoPath)};
}
} else {
String dataString = data.getDataString();
if (dataString != null) {
results = new Uri[]{Uri.parse(dataString)};
}
}
}
mFilePathCallback.onReceiveValue(results);
mFilePathCallback = null;
return;
}
private void goExit(){
try
{
AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this);
b.setTitle("Are You Sure Want to Quit?");
b.setPositiveButton("Yes", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int whichButton)
{
finishScreen();
}
});
b.create().show();
}
catch(Exception ex)
{
}
}
private void finishScreen()
{
this.finish();
}
private void retry(){
mbReloadPressed = true;
wb.reload();
wb.setVisibility(View.VISIBLE);
mlLayoutRequestError.setVisibility(View.GONE);
mbErrorOccured = false;
Intent intent=new Intent(MainActivity.this, MainActivity.class);
startActivity(intent);
finishScreen();
}
private void showErrorLayout() {
wb.stopLoading();
mlLayoutRequestError.setVisibility(View.VISIBLE);
wb.setVisibility(View.GONE);
if(pDialog.isShowing())
pDialog.dismiss();
}
private void hideErrorLayout() {
mhErrorLayoutHide.sendEmptyMessageDelayed(10000, 200);
}
private Handler getErrorLayoutHideHandler() {
return new Handler() {
@Override
public void handleMessage(Message msg) {
mlLayoutRequestError.setVisibility(View.GONE);
super.handleMessage(msg);
}
};
}
/**
* Check All Runtime permission
* @param ctx
* @return
*/
public static Boolean checkRunTimePermission(Activity ctx){
int camera_permit= ContextCompat.checkSelfPermission(ctx, Manifest.permission.CAMERA);
int read_storage=ContextCompat.checkSelfPermission(ctx, Manifest.permission.WRITE_EXTERNAL_STORAGE);
int write_storage=ContextCompat.checkSelfPermission(ctx,Manifest.permission.READ_EXTERNAL_STORAGE);
List<String> list_permission_required=new ArrayList<>();
if(camera_permit!= PackageManager.PERMISSION_GRANTED)
list_permission_required.add(Manifest.permission.CAMERA);
if(read_storage!=PackageManager.PERMISSION_GRANTED)
list_permission_required.add(Manifest.permission.READ_EXTERNAL_STORAGE);
if(write_storage!=PackageManager.PERMISSION_GRANTED)
list_permission_required.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(!(list_permission_required.isEmpty()))
{
ActivityCompat.requestPermissions(ctx,list_permission_required.toArray
(new String[list_permission_required.size()]),Request_Id_Multiple_Permissions);
return false;
}
return true;
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<RelativeLayout
android:id="@+id/common_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="@style/popUpTheme">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="20dp"
android:layout_height="50dp"
android:clickable="true"
android:id="@+id/ic_back"
android:src="@drawable/back_icon"
android:gravity="center_vertical|center_horizontal"
android:layout_marginTop="5dp"
android:layout_marginRight="10dp"
/>
<TextView
android:layout_width="150dp"
android:layout_height="50dp"
android:clickable="true"
android:textSize="20dp"
android:textStyle="bold"
android:textColor="@color/colorWhite"
android:id="@+id/image_view_title"
android:text="@string/app_name"
android:gravity="center_vertical|left"
android:layout_marginTop="5dp"
android:layout_toRightOf="@+id/ic_back"
/>
</RelativeLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
</RelativeLayout>
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_below="@+id/common_header"
android:layout_height="match_parent">
</WebView>
<LinearLayout
android:id="@+id/lLayoutRequestError"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="@color/colorWhite"
android:gravity="center"
android:orientation="vertical"
android:layout_below="@+id/common_header"
android:visibility="gone"
>
<TextView
android:id="@+id/tvError"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Internet Connectivity Not Found.\nPlease Check your Internet Connection and \nTry Again ."
android:textAlignment="center"
android:textColor="@color/colorRed"
/>
<ImageView
android:id="@+id/btnRetry"
android:layout_width="24dp"
android:layout_height="24dp"
android:background="@drawable/blank"
android:src="@drawable/icon_refresh"
android:gravity="center"
android:minWidth="120dp"
android:text="Reload"
android:textSize="20dp"
android:textStyle="bold"
/>
</LinearLayout>
</RelativeLayout>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment