com.moki.touch.fragments.views.WebContent.java Source code

Java tutorial

Introduction

Here is the source code for com.moki.touch.fragments.views.WebContent.java

Source

package com.moki.touch.fragments.views;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.StateListDrawable;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.HttpAuthHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.moki.touch.R;
import com.moki.touch.activities.HomePlaylist;
import com.moki.touch.activities.PlaylistActivity;
import com.moki.touch.base.BaseScreenController;
import com.moki.touch.cache.Downloader;
import com.moki.touch.interfaces.DownloadListener;
import com.moki.touch.models.ContentObject;
import com.moki.touch.util.SettingsUtil;
import com.moki.touch.util.UrlUtil;

import org.json.JSONException;
import org.json.JSONObject;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;

/**
 * Copyright (C) 2014 Moki Mobility Inc.
 * <p/>
 * Licensed under the Apache License, Version 2.0 (the "License")
 * <p/>
 * You may only use this file in compliance with the license
 * <p/>
 * You may obtain a copy of the License at
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

@SuppressWarnings("ConstantConditions")
public class WebContent extends BaseScreenController implements DownloadListener {

    public static final int TO_MILLISECONDS = 1000;
    public static final String DOMAIN_URL = SettingsUtil.DOMAIN_URL;
    public static final String LOGO_LOCATION = "/MokiMDM/CachedItems/";
    public static final String LOGO_DOWNLOAD_COMPLETE = "LogoDownloadComplete";
    private static final String TAG = "WebContent";
    public String userAgent;
    private WebView webView;
    private LinearLayout rootView;
    private String homeUrl;
    private Handler completionHandler = new Handler();
    private boolean showBrowserBar;
    private boolean showNavigationButtons;
    private boolean showNavigationBar;
    private boolean showEndSessionButton;
    private boolean showProgressBar;
    private boolean showLogo;
    private String uploadLogoUrl;
    private EditText addressBar;
    private ArrayList<String> allowedUrls;
    private String styleColor;
    private ProgressBar progressBar;
    private Animation fadeOut;
    private RelativeLayout browserBar;
    private String customAlertMessage;

    public WebContent(Context context) {
        super(context);
        fadeOut = AnimationUtils.loadAnimation(context, android.R.anim.fade_out);
        fadeOut.setAnimationListener(new Animation.AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {

                progressBar.setVisibility(View.GONE);
            }
        });
        customAlertMessage = SettingsUtil.getCustomAlertMessage();
        userAgent = SettingsUtil.getUserAgent();
    }

    @Override
    public void startContent() {
        loadHome();
        setTimer();
    }

    @Override
    public View getView() {
        View emptyView = super.getView();
        if (emptyView != null) {
            return emptyView;
        }
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        rootView = (LinearLayout) inflater.inflate(R.layout.webcontentlayout, null);
        webView = (WebView) rootView.findViewById(R.id.webcontentview);
        configureWebView(context);
        browserBar = (RelativeLayout) rootView.findViewById(R.id.barlayout);
        // this is added so no swipe actions are detected on the browser bar
        browserBar.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return true;
            }
        });
        progressBar = (ProgressBar) rootView.findViewById(R.id.web_progress_bar);
        progressBar.setVisibility(View.GONE);
        rootView.findViewById(R.id.barlayout).setBackgroundColor(Color.parseColor(styleColor));
        configureNavigationBar();

        if (!isHomeMode) {
            // this listener is being added to ensure that touch events bubble up to the correct receivers.
            disableWebView();
        }

        if (!showBrowserBar) {
            browserBar.setVisibility(View.GONE);
        }

        boolean listenForLogo = setLogo();
        if (listenForLogo) {
            registerForLogoDownload();
        }

        return rootView;
    }

    private void disableWebView() {
        webView.setLongClickable(false);
        webView.setClickable(false);
        webView.setFocusableInTouchMode(false);
        rootView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return false;
            }
        });
    }

    private void configureWebView(Context context) {
        if (!userAgent.equals("default")) {
            webView.getSettings().setUserAgentString(userAgent);
        }
        webView.getSettings().setJavaScriptEnabled(true);
        // Set cache size to 32 mb by default. should be more than enough
        webView.getSettings().setAppCacheMaxSize(1024 * 1024 * 32);
        webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);

        String appCachePath = context.getCacheDir().getAbsolutePath();
        webView.getSettings().setAppCachePath(appCachePath);
        webView.getSettings().setAllowFileAccess(true);
        webView.getSettings().setAppCacheEnabled(true);
        webView.getSettings().setDomStorageEnabled(true);
        webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        webView.setWebViewClient(new CustomClient());
        if (showProgressBar) {
            webView.setWebChromeClient(new CustomChromeClient());
        }
    }

    private boolean setLogo() {
        final ImageView logoView = (ImageView) rootView.findViewById(R.id.logo);
        boolean shouldListenForLogo = false;
        if (SettingsUtil.getUploadLogo() != null && !SettingsUtil.getUploadLogo().isEmpty()) {
            final Bitmap bitmapLogo = getLogoBitmap();
            if (bitmapLogo == null) {
                shouldListenForLogo = true;
            } else {
                new AsyncTask<Void, Void, Void>() {
                    @Override
                    protected Void doInBackground(Void... params) {
                        return null;
                    }

                    @Override
                    protected void onPostExecute(Void aVoid) {
                        super.onPostExecute(aVoid);
                        logoView.setImageBitmap(bitmapLogo);
                    }
                }.execute();
            }
        } else {
            logoView.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.mt_web_logo));
        }
        return shouldListenForLogo;
    }

    private Bitmap getLogoBitmap() {
        ContentObject logoObject = new ContentObject(uploadLogoUrl);
        return BitmapFactory.decodeFile(
                Environment.getExternalStorageDirectory() + LOGO_LOCATION + logoObject.getContentFileName());
    }

    @Override
    public void controlChanged() {
        cleanupHistory();
        webView = null;
        rootView = null;
        homeUrl = null;
        completionHandler = null;
        allowedUrls = null;
        Downloader.getInstance().removeListener(this);
        super.controlChanged();
    }

    private void configureNavigationBar() {

        Button back = (Button) rootView.findViewById(R.id.backButton);
        back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                webView.goBack();
            }
        });
        back.setBackgroundDrawable(createButtonStateList(R.drawable.mt_btn_touch_prev, R.drawable.mt_btn_prev));
        Button forward = (Button) rootView.findViewById(R.id.forwardButton);
        forward.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                webView.goForward();
            }
        });
        forward.setBackgroundDrawable(createButtonStateList(R.drawable.mt_btn_touch_next, R.drawable.mt_btn_next));
        Button home = (Button) rootView.findViewById(R.id.homeButton);
        home.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                endSession();
            }
        });
        home.setBackgroundDrawable(createButtonStateList(R.drawable.mt_btn_touch_home, R.drawable.mt_btn_home));
        Button refresh = (Button) rootView.findViewById(R.id.refreshButton);
        refresh.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                webView.reload();
            }
        });
        refresh.setBackgroundDrawable(
                createButtonStateList(R.drawable.mt_btn_touch_refresh, R.drawable.mt_btn_refresh));
        Button endSession = (Button) rootView.findViewById(R.id.endSession);
        endSession.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setupEndSessionAlertDialog();
                endSession();
            }
        });
        endSession.setBackgroundDrawable(createButtonStateList(R.drawable.mt_btn_end, R.drawable.mt_btn_end));
        addressBar = (EditText) rootView.findViewById(R.id.urlBar);
        addressBar.setText(homeUrl);
        addressBar.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                String url = addressBar.getText().toString();
                url = UrlUtil.addHttp(url);
                webView.loadUrl(url);
                return true;
            }
        });
        addressBar.setLongClickable(false);
        if (!isHomeMode) {
            addressBar.setClickable(false);
            addressBar.setFocusable(false);
            addressBar.setFocusableInTouchMode(false);
            back.setClickable(false);
            forward.setClickable(false);
            home.setClickable(false);
            refresh.setClickable(false);
            endSession.setClickable(false);
        }
        ImageView logo = (ImageView) rootView.findViewById(R.id.logo);

        boolean allNavigationItemsDisabled = true;

        if (!showNavigationButtons) {
            back.setVisibility(View.GONE);
            forward.setVisibility(View.GONE);
            refresh.setVisibility(View.GONE);
            home.setVisibility(View.GONE);
        } else {
            allNavigationItemsDisabled = false;
        }

        if (!showLogo) {
            logo.setVisibility(View.GONE);
        } else {
            allNavigationItemsDisabled = false;
        }

        if (!showEndSessionButton) {
            endSession.setVisibility(View.GONE);
        } else {
            allNavigationItemsDisabled = false;
        }

        if (!showNavigationBar) {
            addressBar.setVisibility(View.GONE);
        } else {
            allNavigationItemsDisabled = false;
        }

        if (allNavigationItemsDisabled) {
            browserBar.setVisibility(View.GONE);
        }
    }

    private void endSession() {
        Intent homeIntent = new Intent();
        homeIntent.setAction(PlaylistActivity.HOME_INTENT);
        context.sendBroadcast(homeIntent);
    }

    private void setupEndSessionAlertDialog() {
        cleanupHistory();
        loadHome();
    }

    public void cleanupHistory() {
        try {
            if (webView != null) {
                Log.i(TAG, "clean up history");
                webView.clearHistory();
                webView.clearFormData();
                webView.clearCache(true);
                webView.clearSslPreferences();
                webView.destroy();
                if (context != null) {
                    CookieSyncManager.createInstance(context);
                    CookieManager cookieManager = CookieManager.getInstance();
                    cookieManager.removeAllCookie();
                }
            }
        } catch (Exception e) {
            Log.i(TAG, e.getMessage(), e);
        }
    }

    private StateListDrawable createButtonStateList(int pressedState, int nonPressedState) {
        StateListDrawable stateList = new StateListDrawable();
        stateList.addState(new int[] { android.R.attr.state_pressed },
                context.getResources().getDrawable(pressedState));
        stateList.addState(new int[] { -android.R.attr.state_pressed },
                context.getResources().getDrawable(nonPressedState));

        return stateList;
    }

    public void loadHome() {
        webView.loadUrl(UrlUtil.addHttp(homeUrl));
    }

    private void setTimer() {
        int duration = Integer.parseInt(
                mContentObject.getDuration().isEmpty() ? "10" : mContentObject.getDuration()) * TO_MILLISECONDS;
        if (!isHomeMode) {
            completionHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    contentFinished();
                }
            }, duration);
        }
    }

    private boolean isAllowedUrl(String url) {
        boolean allowed = false;

        //if there are no allowed urls then we are allowed to continue anywhere.
        if (allowedUrls == null || allowedUrls.size() <= 0 || url.equals(homeUrl)) {
            allowed = true;
        }

        if (!allowed) {
            try {
                URI urlToCheck = new URI(UrlUtil.addHttp(url));
                for (String allowedUrl : allowedUrls) {
                    JSONObject urlSettings = new JSONObject(allowedUrl);
                    URI anAllowedUrl = new URI(UrlUtil.addHttp(urlSettings.optString(DOMAIN_URL)));
                    if (compareUrls(urlToCheck.getHost(), anAllowedUrl.getHost())) {
                        allowed = true;
                        break;
                    }
                }
            } catch (JSONException e) {
                Log.e(getClass().getSimpleName(), "Url setting invalid, could not convert to JSONObject");
            } catch (URISyntaxException e) {
                Log.e(getClass().getSimpleName(), "Could not create URI from string");
            }
        }
        return allowed;
    }

    private boolean compareUrls(String check, String allowed) {
        boolean comparison = false;

        if (check == null || allowed == null || (check + allowed).isEmpty()) {
            return comparison;
        }

        try {
            URI checkUri = URI.create(removeWWW(removeEmptyPath(check)));
            URI allowedUri = URI.create(removeWWW(removeEmptyPath(allowed)));
            if (checkUri.equals(allowedUri)) {
                comparison = true;
            }
        } catch (IllegalArgumentException e) {
            Log.e(getClass().getSimpleName(), "url contained an illegal character");
        }

        return comparison;
    }

    private String removeWWW(String url) {
        String returnString = url;
        if (url != null && url.length() > 0) {
            if (url.contains("/www.")) {
                returnString = url.replace("/www.", "/");
            } else if (url.contains("www.")) {
                returnString = url.replace("www.", "");
            }
        }
        return returnString;
    }

    private String removeEmptyPath(String url) {
        String returnString = url;
        if (url != null && url.length() > 0 && url.charAt(url.length() - 1) == '/') {
            returnString = url.substring(0, url.length() - 1);
        }
        return returnString;
    }

    private class CustomClient extends WebViewClient {

        Context context;

        public CustomClient() {
            this.context = HomePlaylist.getContext();
        }

        @Override
        public void onLoadResource(WebView view, String url) {
            super.onLoadResource(view, url);
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            boolean stopLoading = false;

            if (isHomeMode) {
                if (!isAllowedUrl(url)) {
                    stopLoading = true;
                }
            }

            if (stopLoading) {
                showUnallowedSitesWarning();
            }

            return false;
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            if (!isAllowedUrl(url)) {
                webView.stopLoading();
                showUnallowedSitesWarning();
            }
        }

        private void showUnallowedSitesWarning() {
            String alertMessage = customAlertMessage;
            if (customAlertMessage == null || customAlertMessage.isEmpty()) {
                alertMessage = "Site not allowed";
            }
            Toast toast = Toast.makeText(context, alertMessage, Toast.LENGTH_LONG);
            toast.setGravity(Gravity.TOP, 0, 0);
            toast.show();
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            addressBar.setText(url);
        }

        @Override
        public void onReceivedHttpAuthRequest(WebView view, final HttpAuthHandler handler, String host,
                String realm) {
            showAuthenticationDialog(handler);
        }

        private void showAuthenticationDialog(final HttpAuthHandler handler) {
            Dialog passwordDialog;
            if (context != null) {
                final EditText passwordText = new EditText(context);
                passwordText.setHint("password");

                final EditText usernameText = new EditText(context);
                usernameText.setHint("username");

                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
                layoutParams.setMargins(0, 0, 0, 10);

                usernameText.setLayoutParams(layoutParams);
                passwordText.setLayoutParams(layoutParams);

                LinearLayout layout = new LinearLayout(context);
                layout.setOrientation(LinearLayout.VERTICAL);
                layout.addView(usernameText);
                layout.addView(passwordText);

                AlertDialog.Builder builder = new AlertDialog.Builder(context);
                builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        handler.cancel();
                    }
                }).setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                    @SuppressWarnings("ConstantConditions")
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if (passwordText.getText() != null && usernameText.getText() != null) {
                            handler.proceed(usernameText.getText().toString(), passwordText.getText().toString());
                        }
                    }
                }).setTitle("Basic Authentication").setView(layout);
                passwordDialog = builder.create();
                passwordDialog.show();
            } else {
                Log.i("HttpAuth", "context is null");
            }
        }
    }

    private class CustomChromeClient extends WebChromeClient {

        @Override
        public void onProgressChanged(WebView view, int newProgress) {

            if (newProgress > 0 && newProgress < 100) {

                progressBar.setVisibility(View.VISIBLE);

            } else if (newProgress == 100) {

                progressBar.startAnimation(fadeOut);
            }

            progressBar.setProgress(newProgress);
        }
    }

    public void setHomeUrl(String homeUrl) {
        this.homeUrl = UrlUtil.addHttp(homeUrl);
    }

    public void setAllowedUrls(ArrayList<String> allowedUrls) {
        this.allowedUrls = allowedUrls;
    }

    public void setShowBrowserBar(boolean showBrowserBar) {
        this.showBrowserBar = showBrowserBar;
    }

    public void setBarVisibility(boolean showNavigationButtons, boolean showEndSessionButton,
            boolean showNavigationBar) {
        this.showNavigationButtons = showNavigationButtons;
        this.showEndSessionButton = showEndSessionButton;
        this.showNavigationBar = showNavigationBar;
    }

    public void setStyleColor(String styleColor) {
        this.styleColor = styleColor;
    }

    public void setShowProgressBar(boolean showProgressBar) {
        this.showProgressBar = showProgressBar;
    }

    public void setShowLogo(boolean showLogo) {
        this.showLogo = showLogo;
    }

    public void setUploadLogoUrl(String uploadLogoUrl) {
        this.uploadLogoUrl = uploadLogoUrl;
    }

    private void registerForLogoDownload() {
        Downloader.getInstance().registerListener(this);
    }

    @Override
    public boolean downloadFinished(String url) {
        if (url.equals(SettingsUtil.getUploadLogo())) {
            setLogo();
            return true;
        }
        return false;
    }
}