summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java114
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java13
-rw-r--r--chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java12
-rw-r--r--chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java2
-rw-r--r--chrome/browser/content_settings/permission_infobar_delegate.cc5
-rw-r--r--chrome/browser/content_settings/permission_infobar_delegate.h4
-rw-r--r--chrome/browser/media/media_stream_infobar_delegate.cc8
-rw-r--r--chrome/browser/media/media_stream_infobar_delegate.h3
-rw-r--r--chrome/browser/ui/android/infobars/confirm_infobar.cc42
-rw-r--r--components/infobars/core/infobar_delegate.cc4
-rw-r--r--components/infobars/core/infobar_delegate.h2
-rw-r--r--content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java19
-rw-r--r--content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java3
-rw-r--r--ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java81
-rw-r--r--ui/android/java/src/org/chromium/ui/base/WindowAndroid.java38
15 files changed, 318 insertions, 32 deletions
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java
index c33b904..ea4bde7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java
@@ -4,7 +4,18 @@
package org.chromium.chrome.browser.infobar;
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.graphics.Bitmap;
+import android.os.Process;
+
+import org.chromium.chrome.browser.ContentSettingsType;
+import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.base.WindowAndroid.PermissionCallback;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* An infobar that presents the user with several buttons.
@@ -24,6 +35,14 @@ public class ConfirmInfoBar extends InfoBar {
/** Notified when one of the buttons is clicked. */
private final InfoBarListeners.Confirm mConfirmListener;
+ private WindowAndroid mWindowAndroid;
+
+ /**
+ * The list of {@link ContentSettingsType}s being requested by this infobar. Can be null or
+ * empty if none apply.
+ */
+ private int[] mContentSettings;
+
public ConfirmInfoBar(InfoBarListeners.Confirm confirmListener, int iconDrawableId,
Bitmap iconBitmap, String message, String linkText, String primaryButtonText,
String secondaryButtonText) {
@@ -34,13 +53,106 @@ public class ConfirmInfoBar extends InfoBar {
mConfirmListener = confirmListener;
}
+ /**
+ * Specifies the {@link ContentSettingsType}s that are controlled by this InfoBar.
+ *
+ * @param windowAndroid The WindowAndroid that will be used to check for the necessary
+ * permissions.
+ * @param contentSettings The list of {@link ContentSettingsType}s whose access is guarded
+ * by this InfoBar.
+ */
+ protected void setContentSettings(
+ WindowAndroid windowAndroid, int[] contentSettings) {
+ mWindowAndroid = windowAndroid;
+ mContentSettings = contentSettings;
+
+ assert windowAndroid != null
+ : "A WindowAndroid must be specified to request access to content settings";
+ }
+
@Override
public void createContent(InfoBarLayout layout) {
layout.setButtons(mPrimaryButtonText, mSecondaryButtonText, mTertiaryButtonText);
}
+ private static boolean hasPermission(Context context, String permission) {
+ return context.checkPermission(permission, Process.myPid(), Process.myUid())
+ != PackageManager.PERMISSION_DENIED;
+ }
+
+ private List<String> getPermissionsToRequest() {
+ Context context = getContext();
+ List<String> permissionsToRequest = new ArrayList<String>();
+ for (int i = 0; i < mContentSettings.length; i++) {
+ switch (mContentSettings[i]) {
+ case ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION:
+ if (!hasPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)) {
+ permissionsToRequest.add(Manifest.permission.ACCESS_FINE_LOCATION);
+ }
+ break;
+ case ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
+ if (!hasPermission(context, Manifest.permission.CAMERA)) {
+ permissionsToRequest.add(Manifest.permission.CAMERA);
+ }
+ break;
+ case ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
+ if (!hasPermission(context, Manifest.permission.RECORD_AUDIO)) {
+ permissionsToRequest.add(Manifest.permission.RECORD_AUDIO);
+ }
+ break;
+ default:
+ // No associated Android permission, so just skip it.
+ break;
+ }
+ }
+ return permissionsToRequest;
+ }
+
@Override
- public void onButtonClicked(boolean isPrimaryButton) {
+ public void onButtonClicked(final boolean isPrimaryButton) {
+ if (mWindowAndroid == null || mContentSettings == null
+ || !isPrimaryButton || getContext() == null) {
+ onButtonClickedInternal(isPrimaryButton);
+ return;
+ }
+
+ List<String> permissionsToRequest = getPermissionsToRequest();
+ if (permissionsToRequest.isEmpty()) {
+ onButtonClickedInternal(isPrimaryButton);
+ return;
+ }
+
+ PermissionCallback callback = new PermissionCallback() {
+ @Override
+ public void onRequestPermissionsResult(
+ String[] permissions, int[] grantResults) {
+ boolean grantedAllPermissions = true;
+ for (int i = 0; i < grantResults.length; i++) {
+ if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
+ grantedAllPermissions = false;
+ break;
+ }
+ }
+
+ if (!grantedAllPermissions) {
+ onCloseButtonClicked();
+ } else {
+ onButtonClickedInternal(true);
+ }
+ }
+
+ @Override
+ public void onRequestPermissionAborted() {
+ onCloseButtonClicked();
+ }
+ };
+
+ mWindowAndroid.requestPermissions(
+ permissionsToRequest.toArray(new String[permissionsToRequest.size()]),
+ callback);
+ }
+
+ private void onButtonClickedInternal(boolean isPrimaryButton) {
if (mConfirmListener != null) {
mConfirmListener.onConfirmInfoBarButtonClicked(this, isPrimaryButton);
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java
index d5d0ad1..d82b81c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java
@@ -8,6 +8,7 @@ import android.graphics.Bitmap;
import org.chromium.base.CalledByNative;
import org.chromium.chrome.browser.ResourceId;
+import org.chromium.ui.base.WindowAndroid;
/**
* Provides JNI methods for ConfirmInfoBars
@@ -24,22 +25,28 @@ public class ConfirmInfoBarDelegate {
/**
* Creates and begins the process for showing a ConfirmInfoBar.
+ * @param windowAndroid The owning window for the infobar.
* @param enumeratedIconId ID corresponding to the icon that will be shown for the InfoBar.
* The ID must have been mapped using the ResourceMapper class before
* passing it to this function.
- * @param iconBitmap Bitmap to use if there is no equivalent Java resource for enumeratedIconId.
+ * @param iconBitmap Bitmap to use if there is no equivalent Java resource for
+ * enumeratedIconId.
* @param message Message to display to the user indicating what the InfoBar is for.
* @param linkText Link text to display in addition to the message.
* @param buttonOk String to display on the OK button.
* @param buttonCancel String to display on the Cancel button.
+ * @param contentSettings The list of ContentSettingTypes being requested by this infobar.
*/
@CalledByNative
- InfoBar showConfirmInfoBar(int enumeratedIconId, Bitmap iconBitmap, String message,
- String linkText, String buttonOk, String buttonCancel) {
+ InfoBar showConfirmInfoBar(WindowAndroid windowAndroid, int enumeratedIconId,
+ Bitmap iconBitmap, String message, String linkText, String buttonOk,
+ String buttonCancel, int[] contentSettings) {
int drawableId = ResourceId.mapToDrawableId(enumeratedIconId);
ConfirmInfoBar infoBar = new ConfirmInfoBar(
null, drawableId, iconBitmap, message, linkText, buttonOk, buttonCancel);
+ infoBar.setContentSettings(windowAndroid, contentSettings);
+
return infoBar;
}
}
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java
index 9b9e7c5..fd20655 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java
@@ -71,6 +71,7 @@ import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.readback_types.ReadbackResponse;
import org.chromium.printing.PrintManagerDelegateImpl;
import org.chromium.printing.PrintingController;
+import org.chromium.ui.base.ActivityWindowAndroid;
import org.chromium.ui.base.DeviceFormFactor;
import org.chromium.ui.base.PageTransition;
import org.chromium.ui.base.WindowAndroid;
@@ -91,7 +92,7 @@ public abstract class CompositorChromeActivity extends ChromeActivity
private static final String TAG = "CompositorChromeActivity";
- private WindowAndroid mWindowAndroid;
+ private ActivityWindowAndroid mWindowAndroid;
private ChromeFullscreenManager mFullscreenManager;
private CompositorViewHolder mCompositorViewHolder;
private ContextualSearchManager mContextualSearchManager;
@@ -331,6 +332,15 @@ public abstract class CompositorChromeActivity extends ChromeActivity
return mWindowAndroid.onActivityResult(requestCode, resultCode, intent);
}
+ // @Override[ANDROID-M]
+ public void onRequestPermissionsResult(int requestCode, String[] permissions,
+ int[] grantResults) {
+ if (mWindowAndroid != null) {
+ mWindowAndroid.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+ //super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
diff --git a/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java b/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java
index cd2a469..28fa149 100644
--- a/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java
+++ b/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java
@@ -88,7 +88,7 @@ public class ChromeShellActivity extends AppCompatActivity implements AppMenuPro
}
};
- private WindowAndroid mWindow;
+ private ActivityWindowAndroid mWindow;
private TabManager mTabManager;
private ChromeShellToolbar mToolbar;
private DevToolsServer mDevToolsServer;
diff --git a/chrome/browser/content_settings/permission_infobar_delegate.cc b/chrome/browser/content_settings/permission_infobar_delegate.cc
index 6117827..4ff0975 100644
--- a/chrome/browser/content_settings/permission_infobar_delegate.cc
+++ b/chrome/browser/content_settings/permission_infobar_delegate.cc
@@ -34,6 +34,11 @@ void PermissionInfobarDelegate::InfoBarDismissed() {
SetPermission(false, false);
}
+PermissionInfobarDelegate*
+PermissionInfobarDelegate::AsPermissionInfobarDelegate() {
+ return this;
+}
+
base::string16 PermissionInfobarDelegate::GetButtonLabel(
InfoBarButton button) const {
return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
diff --git a/chrome/browser/content_settings/permission_infobar_delegate.h b/chrome/browser/content_settings/permission_infobar_delegate.h
index 25bb0b4..519fbca 100644
--- a/chrome/browser/content_settings/permission_infobar_delegate.h
+++ b/chrome/browser/content_settings/permission_infobar_delegate.h
@@ -20,6 +20,9 @@ class PermissionQueueController;
// provide an icon and a message text to the infobar.
class PermissionInfobarDelegate : public ConfirmInfoBarDelegate {
+ public:
+ ContentSettingsType content_setting() const { return type_; }
+
protected:
PermissionInfobarDelegate(PermissionQueueController* controller,
const PermissionRequestID& id,
@@ -31,6 +34,7 @@ class PermissionInfobarDelegate : public ConfirmInfoBarDelegate {
// ConfirmInfoBarDelegate:
Type GetInfoBarType() const override;
void InfoBarDismissed() override;
+ PermissionInfobarDelegate* AsPermissionInfobarDelegate() override;
base::string16 GetButtonLabel(InfoBarButton button) const override;
bool Accept() override;
bool Cancel() override;
diff --git a/chrome/browser/media/media_stream_infobar_delegate.cc b/chrome/browser/media/media_stream_infobar_delegate.cc
index 6cc451b..6c9c1c0 100644
--- a/chrome/browser/media/media_stream_infobar_delegate.cc
+++ b/chrome/browser/media/media_stream_infobar_delegate.cc
@@ -66,6 +66,14 @@ bool MediaStreamInfoBarDelegate::Create(
return true;
}
+bool MediaStreamInfoBarDelegate::IsRequestingVideoAccess() const {
+ return controller_->HasVideo();
+}
+
+bool MediaStreamInfoBarDelegate::IsRequestingMicrophoneAccess() const {
+ return controller_->HasAudio();
+}
+
MediaStreamInfoBarDelegate::MediaStreamInfoBarDelegate(
scoped_ptr<MediaStreamDevicesController> controller)
: ConfirmInfoBarDelegate(),
diff --git a/chrome/browser/media/media_stream_infobar_delegate.h b/chrome/browser/media/media_stream_infobar_delegate.h
index e055289..4f86c71 100644
--- a/chrome/browser/media/media_stream_infobar_delegate.h
+++ b/chrome/browser/media/media_stream_infobar_delegate.h
@@ -30,6 +30,9 @@ class MediaStreamInfoBarDelegate : public ConfirmInfoBarDelegate {
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback);
+ bool IsRequestingVideoAccess() const;
+ bool IsRequestingMicrophoneAccess() const;
+
private:
friend class WebRtcTestBase;
diff --git a/chrome/browser/ui/android/infobars/confirm_infobar.cc b/chrome/browser/ui/android/infobars/confirm_infobar.cc
index 9fef5cf..43dcc78 100644
--- a/chrome/browser/ui/android/infobars/confirm_infobar.cc
+++ b/chrome/browser/ui/android/infobars/confirm_infobar.cc
@@ -4,13 +4,22 @@
#include "chrome/browser/ui/android/infobars/confirm_infobar.h"
+#include <vector>
+
#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/logging.h"
#include "chrome/browser/android/resource_mapper.h"
+#include "chrome/browser/content_settings/permission_infobar_delegate.h"
#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/media/media_stream_infobar_delegate.h"
+#include "components/content_settings/core/common/content_settings_types.h"
#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "content/public/browser/android/content_view_core.h"
+#include "content/public/browser/web_contents.h"
#include "jni/ConfirmInfoBarDelegate_jni.h"
+#include "ui/android/window_android.h"
#include "ui/gfx/android/java_bitmap.h"
#include "ui/gfx/image/image.h"
@@ -53,10 +62,37 @@ base::android::ScopedJavaLocalRef<jobject> ConfirmInfoBar::CreateRenderInfoBar(
java_bitmap = gfx::ConvertToJavaBitmap(delegate->GetIcon().ToSkBitmap());
}
+ std::vector<int> content_settings;
+ if (delegate->AsPermissionInfobarDelegate()) {
+ content_settings.push_back(
+ delegate->AsPermissionInfobarDelegate()->content_setting());
+ } else if (delegate->AsMediaStreamInfoBarDelegate()) {
+ MediaStreamInfoBarDelegate* media_delegate =
+ delegate->AsMediaStreamInfoBarDelegate();
+ if (media_delegate->IsRequestingVideoAccess()) {
+ content_settings.push_back(
+ ContentSettingsType::CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
+ } else if (media_delegate->IsRequestingMicrophoneAccess()) {
+ content_settings.push_back(
+ ContentSettingsType::CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
+ }
+ }
+
+ content::WebContents* web_contents =
+ InfoBarService::WebContentsFromInfoBar(this);
+ DCHECK(web_contents);
+ content::ContentViewCore* cvc =
+ content::ContentViewCore::FromWebContents(web_contents);
+ DCHECK(cvc);
+ base::android::ScopedJavaLocalRef<jobject> jwindow_android =
+ cvc->GetWindowAndroid()->GetJavaObject();
+
return Java_ConfirmInfoBarDelegate_showConfirmInfoBar(
- env, java_confirm_delegate_.obj(), GetEnumeratedIconId(),
- java_bitmap.obj(), message_text.obj(), link_text.obj(),
- ok_button_text.obj(), cancel_button_text.obj());
+ env, java_confirm_delegate_.obj(),
+ jwindow_android.obj(), GetEnumeratedIconId(), java_bitmap.obj(),
+ message_text.obj(), link_text.obj(), ok_button_text.obj(),
+ cancel_button_text.obj(),
+ base::android::ToJavaIntArray(env, content_settings).obj());
}
void ConfirmInfoBar::OnLinkClicked(JNIEnv* env, jobject obj) {
diff --git a/components/infobars/core/infobar_delegate.cc b/components/infobars/core/infobar_delegate.cc
index 37fbdf7..d9f7655 100644
--- a/components/infobars/core/infobar_delegate.cc
+++ b/components/infobars/core/infobar_delegate.cc
@@ -68,6 +68,10 @@ NativeAppInfoBarDelegate* InfoBarDelegate::AsNativeAppInfoBarDelegate() {
return nullptr;
}
+PermissionInfobarDelegate* InfoBarDelegate::AsPermissionInfobarDelegate() {
+ return nullptr;
+}
+
PopupBlockedInfoBarDelegate* InfoBarDelegate::AsPopupBlockedInfoBarDelegate() {
return nullptr;
}
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index ec6cd82..4c1e234 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -14,6 +14,7 @@ class ConfirmInfoBarDelegate;
class InsecureContentInfoBarDelegate;
class MediaStreamInfoBarDelegate;
class NativeAppInfoBarDelegate;
+class PermissionInfobarDelegate;
class PopupBlockedInfoBarDelegate;
class RegisterProtocolHandlerInfoBarDelegate;
class ScreenCaptureInfoBarDelegate;
@@ -114,6 +115,7 @@ class InfoBarDelegate {
virtual InsecureContentInfoBarDelegate* AsInsecureContentInfoBarDelegate();
virtual MediaStreamInfoBarDelegate* AsMediaStreamInfoBarDelegate();
virtual NativeAppInfoBarDelegate* AsNativeAppInfoBarDelegate();
+ virtual PermissionInfobarDelegate* AsPermissionInfobarDelegate();
virtual PopupBlockedInfoBarDelegate* AsPopupBlockedInfoBarDelegate();
virtual RegisterProtocolHandlerInfoBarDelegate*
AsRegisterProtocolHandlerInfoBarDelegate();
diff --git a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java
index f13e348..aa7a08a 100644
--- a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java
+++ b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java
@@ -24,7 +24,6 @@ import org.chromium.content.browser.ContentViewCore;
import org.chromium.content_shell.Shell;
import org.chromium.content_shell.ShellManager;
import org.chromium.ui.base.ActivityWindowAndroid;
-import org.chromium.ui.base.WindowAndroid;
/**
* Test activity used for verifying the different configuration options for the ContentLinker.
@@ -43,7 +42,7 @@ public class ChromiumLinkerTestActivity extends Activity {
private static final String LOW_MEMORY_DEVICE = "--low-memory-device";
private ShellManager mShellManager;
- private WindowAndroid mWindowAndroid;
+ private ActivityWindowAndroid mWindowAndroid;
@Override
public void onCreate(final Bundle savedInstanceState) {
@@ -63,21 +62,21 @@ public class ChromiumLinkerTestActivity extends Activity {
// reason, so parse the command-line differently here:
boolean hasLowMemoryDeviceSwitch = false;
String[] cmdline = CommandLine.getJavaSwitchesOrNull();
- if (cmdline == null)
+ if (cmdline == null) {
Log.i(TAG, "Command line is null");
- else {
+ } else {
Log.i(TAG, "Command line is:");
for (int n = 0; n < cmdline.length; ++n) {
Log.i(TAG, " '" + cmdline[n] + "'");
- if (cmdline[n].equals(LOW_MEMORY_DEVICE))
- hasLowMemoryDeviceSwitch = true;
+ if (cmdline[n].equals(LOW_MEMORY_DEVICE)) hasLowMemoryDeviceSwitch = true;
}
}
// Determine which kind of device to simulate from the command-line.
int memoryDeviceConfig = Linker.MEMORY_DEVICE_CONFIG_NORMAL;
- if (hasLowMemoryDeviceSwitch)
+ if (hasLowMemoryDeviceSwitch) {
memoryDeviceConfig = Linker.MEMORY_DEVICE_CONFIG_LOW;
+ }
Linker.setMemoryDeviceConfig(memoryDeviceConfig);
// Register the test runner class by name.
@@ -185,12 +184,14 @@ public class ChromiumLinkerTestActivity extends Activity {
* one is not showing.
*/
public ContentViewCore getActiveContentViewCore() {
- if (mShellManager == null)
+ if (mShellManager == null) {
return null;
+ }
Shell shell = mShellManager.getActiveShell();
- if (shell == null)
+ if (shell == null) {
return null;
+ }
return shell.getContentViewCore();
}
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
index ea0c4e6..a394a1b 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
@@ -28,7 +28,6 @@ import org.chromium.content_public.browser.WebContents;
import org.chromium.content_shell.Shell;
import org.chromium.content_shell.ShellManager;
import org.chromium.ui.base.ActivityWindowAndroid;
-import org.chromium.ui.base.WindowAndroid;
/**
* Activity for managing the Content Shell.
@@ -41,7 +40,7 @@ public class ContentShellActivity extends Activity {
public static final String COMMAND_LINE_ARGS_KEY = "commandLineArgs";
private ShellManager mShellManager;
- private WindowAndroid mWindowAndroid;
+ private ActivityWindowAndroid mWindowAndroid;
private Intent mLastSentIntent;
@Override
diff --git a/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java
index c83a0ca..6e6e308 100644
--- a/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java
@@ -9,6 +9,8 @@ import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
+import android.os.Handler;
+import android.util.SparseArray;
import android.view.View;
import org.chromium.base.ActivityState;
@@ -16,6 +18,8 @@ import org.chromium.base.ApplicationStatus;
import org.chromium.ui.UiUtils;
import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
/**
* The class provides the WindowAndroid's implementation which requires
@@ -31,6 +35,12 @@ public class ActivityWindowAndroid
private static final String TAG = "ActivityWindowAndroid";
private final WeakReference<Activity> mActivityRef;
+ private final Handler mHandler;
+ private final SparseArray<PermissionCallback> mOutstandingPermissionRequests;
+ private final Runnable mClearPermissionRequestsTask;
+
+ private Method mRequestPermissionsMethod;
+
private int mNextRequestCode = 0;
/**
@@ -51,6 +61,17 @@ public class ActivityWindowAndroid
public ActivityWindowAndroid(Activity activity, boolean listenToActivityState) {
super(activity.getApplicationContext());
mActivityRef = new WeakReference<Activity>(activity);
+ mHandler = new Handler();
+ mOutstandingPermissionRequests = new SparseArray<PermissionCallback>();
+ mClearPermissionRequestsTask = new Runnable() {
+ @Override
+ public void run() {
+ for (int i = 0; i < mOutstandingPermissionRequests.size(); i++) {
+ mOutstandingPermissionRequests.valueAt(i).onRequestPermissionAborted();
+ }
+ mOutstandingPermissionRequests.clear();
+ }
+ };
if (listenToActivityState) {
ApplicationStatus.registerStateListenerForActivity(this, activity);
}
@@ -113,7 +134,13 @@ public class ActivityWindowAndroid
activity.finishActivity(requestCode);
}
- @Override
+ /**
+ * Responds to the intent result if the intent was created by the native window.
+ * @param requestCode Request code of the requested intent.
+ * @param resultCode Result code of the requested intent.
+ * @param data The data returned by the intent.
+ * @return Boolean value of whether the intent was started by the native window.
+ */
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
IntentCallback callback = mOutstandingIntents.get(requestCode);
mOutstandingIntents.delete(requestCode);
@@ -133,6 +160,53 @@ public class ActivityWindowAndroid
}
@Override
+ public void requestPermissions(String[] permissions, PermissionCallback callback) {
+ mHandler.removeCallbacks(mClearPermissionRequestsTask);
+
+ // TODO(tedchoc): Remove the reflection aspect of this once a public M SDK is available.
+ Activity activity = mActivityRef.get();
+ if (activity == null) return;
+
+ if (mRequestPermissionsMethod == null) {
+ try {
+ mRequestPermissionsMethod = Activity.class.getMethod(
+ "requestPermissions", String[].class, int.class);
+ } catch (NoSuchMethodException e) {
+ return;
+ }
+ }
+
+ int requestCode = generateNextRequestCode();
+ mOutstandingPermissionRequests.put(requestCode, callback);
+
+ try {
+ mRequestPermissionsMethod.invoke(activity, permissions, requestCode);
+ } catch (IllegalAccessException e) {
+ mOutstandingPermissionRequests.delete(requestCode);
+ } catch (IllegalArgumentException e) {
+ mOutstandingPermissionRequests.delete(requestCode);
+ } catch (InvocationTargetException e) {
+ mOutstandingPermissionRequests.delete(requestCode);
+ }
+ }
+
+ /**
+ * Responds to a pending permission result.
+ * @param requestCode The unique code for the permission request.
+ * @param permissions The list of permissions in the result.
+ * @param grantResults Whether the permissions were granted.
+ * @return Whether the permission request corresponding to a pending permission request.
+ */
+ public boolean onRequestPermissionsResult(int requestCode, String[] permissions,
+ int[] grantResults) {
+ PermissionCallback callback = mOutstandingPermissionRequests.get(requestCode);
+ mOutstandingPermissionRequests.delete(requestCode);
+ if (callback == null) return false;
+ callback.onRequestPermissionsResult(permissions, grantResults);
+ return true;
+ }
+
+ @Override
public WeakReference<Activity> getActivity() {
// Return a new WeakReference to prevent clients from releasing our internal WeakReference.
return new WeakReference<Activity>(mActivityRef.get());
@@ -144,6 +218,11 @@ public class ActivityWindowAndroid
onActivityPaused();
} else if (newState == ActivityState.RESUMED) {
onActivityResumed();
+
+ // Work around an issue where we do not always get an onRequestPermissionsResult
+ // callback if the user hits the back button in the permission dialog instead
+ // of taking an action.
+ mHandler.post(mClearPermissionRequestsTask);
}
}
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
index 84a3499..d0dde3d 100644
--- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
@@ -214,6 +214,16 @@ public class WindowAndroid {
}
/**
+ * Requests the specified permissions are granted for further use.
+ * @param permissions The list of permissions to request access to.
+ * @param callback The callback to be notified whether the permissions were granted.
+ */
+ public void requestPermissions(String[] permissions, PermissionCallback callback) {
+ Log.w(TAG, "Cannot request permissions as the context is not an Activity");
+ assert false : "Failed to request permissions using a WindowAndroid without an Activity";
+ }
+
+ /**
* Displays an error message with a provided error message string.
* @param error The error message string to be displayed.
*/
@@ -305,17 +315,6 @@ public class WindowAndroid {
nativeOnActivityResumed(mNativeWindowAndroid);
}
- /**
- * Responds to the intent result if the intent was created by the native window.
- * @param requestCode Request code of the requested intent.
- * @param resultCode Result code of the requested intent.
- * @param data The data returned by the intent.
- * @return Boolean value of whether the intent was started by the native window.
- */
- public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
- return false;
- }
-
@CalledByNative
private void requestVSyncUpdate() {
mVSyncMonitor.requestUpdate();
@@ -337,6 +336,23 @@ public class WindowAndroid {
}
/**
+ * Callback for permission requests.
+ */
+ public interface PermissionCallback {
+ /**
+ * Called upon completing a permission request.
+ * @param permissions The list of permissions in the result.
+ * @param grantResults Whether the permissions were granted.
+ */
+ void onRequestPermissionsResult(String[] permissions, int[] grantResults);
+
+ /**
+ * Called when a permission request has been aborted.
+ */
+ void onRequestPermissionAborted();
+ }
+
+ /**
* Tests that an activity is available to handle the passed in intent.
* @param intent The intent to check.
* @return True if an activity is available to process this intent when started, meaning that