/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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. */ package com.android.tv.settings.dialog.old; import android.annotation.TargetApi; import android.app.Activity; import android.app.Fragment; import android.content.Context; import android.content.res.Configuration; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Message; import android.provider.Settings; import android.provider.Settings.Secure; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.webkit.CookieManager; import android.webkit.CookieSyncManager; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import com.android.tv.settings.R; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; import java.util.Locale; /** * Fragment that shows a link containing the ToS. */ public class TosWebViewFragment extends Fragment { private static final String TAG = "TosWebViewFragment"; private static final boolean DEBUG = false; // TODO switch to pointing to proper TLD once there is a reliable way to // map geography to proper TLD, b/11032160 private static final String GOOGLE_TOS_URL = "http://www.google.com/intl/%y_%z/policies/terms/"; private static final String GOOGLE_PRIVACY_URL = "http://www.google.com/intl/%y_%z/policies/privacy/"; private static final String SETTINGS_SECURE_TOS_URL = "canvas_tos_url"; private static final String SETTINGS_SECURE_PRIVACY_URL = "canvas_privacy_url"; private static final int SOURCE_URL = 1; private static final int SOURCE_STRING = 2; private static final int SOURCE_RESOURCE_ID = 3; private static final String ARGUMENT_SHOW = "show"; private static final String ARGUMENT_CONTENT_STRING = "content_string"; private static final String ARGUMENT_CONTENT_URL = "content_url"; private static final String ARGUMENT_CONTENT_RESOURCE_ID = "content_resource_id"; public static final int SHOW_TERMS_OF_SERVICE = 3; public static final int SHOW_PRIVACY_POLICY = 4; public static final int SHOW_ADDITIONAL_TERMS = 5; /** * Create instance and select page to display. The content is selected by the single parameter * and determined by a URL or resource string depending on the page to show. * * @param show One of SHOW_TERMS_OF_SERVICE, SHOW_PRIVACY_POLICY, SHOW_ADDITIONAL_TERMS */ public static TosWebViewFragment newInstance(int show) { TosWebViewFragment f = new TosWebViewFragment(); Bundle args = new Bundle(); args.putInt(ARGUMENT_SHOW, show); f.setArguments(args); return f; } /** * Create instance and display page from URL. * * @param uri URL of page to show. */ public static TosWebViewFragment newInstanceUrl(String pageUrl) { TosWebViewFragment f = new TosWebViewFragment(); Bundle args = new Bundle(); args.putString(ARGUMENT_CONTENT_URL, pageUrl); f.setArguments(args); return f; } /** * Create instance and display page from a string. * * @param page Text to show. */ public static TosWebViewFragment newInstance(String page) { TosWebViewFragment f = new TosWebViewFragment(); Bundle args = new Bundle(); args.putString(ARGUMENT_CONTENT_STRING, page); f.setArguments(args); return f; } /** * Create instance and display page from resource id. * * @param resourceId id or string resourse to show. */ public static TosWebViewFragment newInstance_resourceId(int resourceId) { TosWebViewFragment f = new TosWebViewFragment(); Bundle args = new Bundle(); args.putInt(ARGUMENT_CONTENT_RESOURCE_ID, resourceId); f.setArguments(args); return f; } private class MyChromeClient extends WebChromeClient { @Override public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture, Message resultMsg) { resultMsg.obj = mWebView; resultMsg.sendToTarget(); return true; } @Override public void onProgressChanged(WebView view, int newProgress) { } @Override public boolean onConsoleMessage(android.webkit.ConsoleMessage consoleMessage) { return true; } } private class MyWebViewClient extends WebViewClient { /** * Before we load any page, we check with our session object to see if * we should do any special handling at this point */ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { return false; } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { Log.w(TAG, String.format( "onReceivedError: errorCode %d, description: %s, url: %s", errorCode, description, failingUrl)); mIsLoading = false; // If this is the first attempted page load, this could be a // connectivity issue // We treat it all as server error, let ShowError decide if network // is still up onWebLoginError(errorCode, description); super.onReceivedError(view, errorCode, description, failingUrl); } @Override public void onTooManyRedirects(WebView view, Message cancelMsg, Message continueMsg) { Log.e(TAG, "onTooManyRedirects"); // Users probably don't care about redirects, it's a server error to // them onWebLoginError(0, ""); } @Override public void onPageFinished(WebView view, String url) { if (DEBUG) { Log.d(TAG, "Loaded " + url); } view.requestFocus(); } private void onWebLoginError(int errorCode, String description) { // TODO: Show error? } } private WebView mWebView; private String mSource; private int mSourceType; private boolean mIsLoading; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle) { View content = inflater.inflate(R.layout.navigable_webview, null); if (icicle == null) { mWebView = (WebView) content.findViewById(R.id.webview); CookieSyncManager.createInstance(getActivity()); mWebView.setWebViewClient(new MyWebViewClient()); mWebView.setWebChromeClient(new MyChromeClient()); WebSettings s = mWebView.getSettings(); s.setNeedInitialFocus(true); s.setJavaScriptEnabled(true); s.setSupportMultipleWindows(false); s.setSaveFormData(false); s.setSavePassword(false); s.setAllowFileAccess(false); s.setDatabaseEnabled(false); s.setJavaScriptCanOpenWindowsAutomatically(false); s.setLoadsImagesAutomatically(true); s.setLightTouchEnabled(false); s.setNeedInitialFocus(false); s.setUseWideViewPort(true); s.setSupportZoom(false); mWebView.setMapTrackballToArrowKeys(false); int show = getArguments().getInt(ARGUMENT_SHOW, -1); switch (show) { case SHOW_TERMS_OF_SERVICE: mSourceType = SOURCE_URL; mSource = Settings.Secure.getString(getActivity().getContentResolver(), SETTINGS_SECURE_TOS_URL); if (mSource == null) { mSource = GOOGLE_TOS_URL; } mSource = substitueArguments(mSource); break; case SHOW_PRIVACY_POLICY: mSourceType = SOURCE_URL; mSource = Settings.Secure.getString(getActivity().getContentResolver(), SETTINGS_SECURE_PRIVACY_URL); if (mSource == null) { mSource = GOOGLE_PRIVACY_URL; } mSource = substitueArguments(mSource); break; case SHOW_ADDITIONAL_TERMS: mSourceType = SOURCE_STRING; mSource = readStringFromResource(getActivity(), R.raw.additional_terms_of_service); break; default: // User is specifying a page to display, either by Url, resource id or string. mSource = getArguments().getString(ARGUMENT_CONTENT_URL); if (mSource != null) { mSourceType = SOURCE_URL; mSource = substitueArguments(mSource); } else { mSourceType = SOURCE_STRING; mSource = getArguments().getString(ARGUMENT_CONTENT_STRING); if (mSource == null) { int resourceId = getArguments().getInt(ARGUMENT_CONTENT_RESOURCE_ID); mSource = getResources().getString(resourceId); } } break; } } return content; } /** * Determines the current activity mode and initializes ui appropriately. */ @Override public void onResume() { super.onResume(); mIsLoading = true; switch (mSourceType) { case SOURCE_URL: mWebView.loadUrl(mSource); break; case SOURCE_STRING: mWebView.loadData(mSource,"text/html", null); break; } mWebView.onResume(); } /** * Stops page loading if it is in progress. */ @Override public void onPause() { if (mIsLoading) { mWebView.stopLoading(); mIsLoading = false; } mWebView.onPause(); super.onPause(); } private String substitueArguments(String url) { // Substitute locale if present in property if (url.contains("%m")) { try { Configuration config = new Configuration(); Settings.System.getConfiguration(getActivity().getContentResolver(), config); if (config.mcc != 0) { url = url.replace("%m", Integer.toString(config.mcc)); } else { // This will happen if the device doesn't have a SIM, in // which case we just use the locale. url = url.replace("%m", "%s"); } } catch (Exception e) { // Intentionally left blank } } if (url.contains("%s")) { Locale locale = Locale.getDefault(); String tmp = locale.getLanguage() + "_" + locale.getCountry().toLowerCase(); url = url.replace("%s", tmp); } // %y is used to indicate a language variable to be replaced at runtime. if (url.contains("%y")) { Locale locale = Locale.getDefault(); url = url.replace("%y", locale.getLanguage()); } // %z is used to indicate the country. We use the value set by the // SIM. We choose not to use the operator/network country but that // which is set on SIM as they most likely procured the device there if (url.contains("%z")) { try { TelephonyManager telephony = (TelephonyManager) getActivity() .getSystemService(Context.TELEPHONY_SERVICE); Configuration config = new Configuration(); Settings.System.getConfiguration(getActivity().getContentResolver(), config); if (telephony != null && config.mcc != 0) { String simCountryIso = telephony.getSimCountryIso(); if (TextUtils.isEmpty(simCountryIso)) { simCountryIso = "us"; } url = url.replace("%z", simCountryIso); } else { // This will happen if the device doesn't have a SIM, in // which case we just use the country with the default // locale country Locale locale = Locale.getDefault(); url = url.replace("%z", locale.getCountry().toLowerCase()); } } catch (Exception e) { // Intentionally left blank } } return url; } private String readStringFromResource(Context context, int resourceId) { StringBuilder contents = new StringBuilder(); String sep = System.lineSeparator(); try { InputStream is = context.getResources().openRawResource(resourceId); BufferedReader input = new BufferedReader(new InputStreamReader(is), 1024*8); try { String line = null; while ((line = input.readLine()) != null) { contents.append(line); contents.append(sep); } } finally { input.close(); } } catch (FileNotFoundException ex) { Log.e(TAG, "Couldn't find the file " + resourceId + " " + ex); return null; } catch (IOException ex){ Log.e(TAG, "Error reading file " + resourceId + " " + ex); return null; } return contents.toString(); } }