1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.permissionrequest;
18 
19 import android.annotation.SuppressLint;
20 import android.os.Bundle;
21 import android.support.annotation.NonNull;
22 import android.support.annotation.Nullable;
23 import android.support.v4.app.DialogFragment;
24 import android.support.v4.app.Fragment;
25 import android.view.LayoutInflater;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.webkit.ConsoleMessage;
29 import android.webkit.PermissionRequest;
30 import android.webkit.WebChromeClient;
31 import android.webkit.WebSettings;
32 import android.webkit.WebView;
33 
34 import com.example.android.common.logger.Log;
35 
36 /**
37  * This fragment shows a {@link WebView} and loads a web app from the {@link SimpleWebServer}.
38  */
39 public class PermissionRequestFragment extends Fragment
40         implements ConfirmationDialogFragment.Listener {
41 
42     private static final String TAG = PermissionRequestFragment.class.getSimpleName();
43 
44     private static final String FRAGMENT_DIALOG = "dialog";
45 
46     /**
47      * We use this web server to serve HTML files in the assets folder. This is because we cannot
48      * use the JavaScript method "getUserMedia" from "file:///android_assets/..." URLs.
49      */
50     private SimpleWebServer mWebServer;
51 
52     /**
53      * A reference to the {@link WebView}.
54      */
55     private WebView mWebView;
56 
57     /**
58      * This field stores the {@link PermissionRequest} from the web application until it is allowed
59      * or denied by user.
60      */
61     private PermissionRequest mPermissionRequest;
62 
63     /**
64      * For testing.
65      */
66     private ConsoleMonitor mConsoleMonitor;
67 
68     @Override
onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)69     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
70                              @Nullable Bundle savedInstanceState) {
71         return inflater.inflate(R.layout.fragment_permission_request, container, false);
72     }
73 
74     @Override
onViewCreated(View view, @Nullable Bundle savedInstanceState)75     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
76         mWebView = (WebView) view.findViewById(R.id.web_view);
77         // Here, we use #mWebChromeClient with implementation for handling PermissionRequests.
78         mWebView.setWebChromeClient(mWebChromeClient);
79         configureWebSettings(mWebView.getSettings());
80     }
81 
82     @Override
onResume()83     public void onResume() {
84         super.onResume();
85         final int port = 8080;
86         mWebServer = new SimpleWebServer(port, getResources().getAssets());
87         mWebServer.start();
88         mWebView.loadUrl("http://localhost:" + port + "/sample.html");
89     }
90 
91     @Override
onPause()92     public void onPause() {
93         mWebServer.stop();
94         super.onPause();
95     }
96 
97     @SuppressLint("SetJavaScriptEnabled")
configureWebSettings(WebSettings settings)98     private static void configureWebSettings(WebSettings settings) {
99         settings.setJavaScriptEnabled(true);
100     }
101 
102     /**
103      * This {@link WebChromeClient} has implementation for handling {@link PermissionRequest}.
104      */
105     private WebChromeClient mWebChromeClient = new WebChromeClient() {
106 
107         // This method is called when the web content is requesting permission to access some
108         // resources.
109         @Override
110         public void onPermissionRequest(PermissionRequest request) {
111             Log.i(TAG, "onPermissionRequest");
112             mPermissionRequest = request;
113             ConfirmationDialogFragment.newInstance(request.getResources())
114                     .show(getChildFragmentManager(), FRAGMENT_DIALOG);
115         }
116 
117         // This method is called when the permission request is canceled by the web content.
118         @Override
119         public void onPermissionRequestCanceled(PermissionRequest request) {
120             Log.i(TAG, "onPermissionRequestCanceled");
121             // We dismiss the prompt UI here as the request is no longer valid.
122             mPermissionRequest = null;
123             DialogFragment fragment = (DialogFragment) getChildFragmentManager()
124                     .findFragmentByTag(FRAGMENT_DIALOG);
125             if (null != fragment) {
126                 fragment.dismiss();
127             }
128         }
129 
130         @Override
131         public boolean onConsoleMessage(@NonNull ConsoleMessage message) {
132             switch (message.messageLevel()) {
133                 case TIP:
134                     Log.v(TAG, message.message());
135                     break;
136                 case LOG:
137                     Log.i(TAG, message.message());
138                     break;
139                 case WARNING:
140                     Log.w(TAG, message.message());
141                     break;
142                 case ERROR:
143                     Log.e(TAG, message.message());
144                     break;
145                 case DEBUG:
146                     Log.d(TAG, message.message());
147                     break;
148             }
149             if (null != mConsoleMonitor) {
150                 mConsoleMonitor.onConsoleMessage(message);
151             }
152             return true;
153         }
154 
155     };
156 
157     @Override
onConfirmation(boolean allowed)158     public void onConfirmation(boolean allowed) {
159         if (allowed) {
160             mPermissionRequest.grant(mPermissionRequest.getResources());
161             Log.d(TAG, "Permission granted.");
162         } else {
163             mPermissionRequest.deny();
164             Log.d(TAG, "Permission request denied.");
165         }
166         mPermissionRequest = null;
167     }
168 
setConsoleMonitor(ConsoleMonitor monitor)169     public void setConsoleMonitor(ConsoleMonitor monitor) {
170         mConsoleMonitor = monitor;
171     }
172 
173     /**
174      * For testing.
175      */
176     public interface ConsoleMonitor {
onConsoleMessage(ConsoleMessage message)177         public void onConsoleMessage(ConsoleMessage message);
178     }
179 
180 }
181