Upstreaming SelectFileDialog for Android
Upstreaming the Select File Dialog and its dependencies needed for Chrome on Android BUG=116131 Review URL: https://chromiumcodereview.appspot.com/10916160 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@157424 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
base/android/jni_generator
chrome
android
java
src
org
chromium
chrome
browser
chrome.gypcontent
DEPS
app
android
browser
content.gypcontent_shell.gypipublic
android
java
src
org
chromium
browser
android
shell
android
java
src
org
chromium
content_shell
ui
@ -151,6 +151,7 @@ def JavaParamToJni(param):
|
||||
'Lcom/google/android/apps/chrome/AutofillData',
|
||||
'Lcom/google/android/apps/chrome/ChromeHttpAuthHandler',
|
||||
'Lcom/google/android/apps/chrome/ChromeContextMenuInfo',
|
||||
'Lcom/google/android/apps/chrome/ChromeWindow',
|
||||
'Lcom/google/android/apps/chrome/OmniboxSuggestion',
|
||||
'Lcom/google/android/apps/chrome/PageInfoViewer',
|
||||
'Lcom/google/android/apps/chrome/Tab',
|
||||
@ -170,7 +171,6 @@ def JavaParamToJni(param):
|
||||
'Lorg/chromium/chrome/browser/FindNotificationDetails',
|
||||
'Lorg/chromium/chrome/browser/JavascriptAppModalDialog',
|
||||
'Lorg/chromium/chrome/browser/ProcessUtils',
|
||||
'Lorg/chromium/chrome/browser/SelectFileDialog',
|
||||
'Lorg/chromium/chrome/browser/component/web_contents_delegate_android/WebContentsDelegateAndroid',
|
||||
'Lorg/chromium/content/browser/ContentVideoView',
|
||||
'Lorg/chromium/content/browser/ContentViewClient',
|
||||
@ -191,6 +191,8 @@ def JavaParamToJni(param):
|
||||
'Lorg/chromium/media/MediaPlayerListener',
|
||||
'Lorg/chromium/net/NetworkChangeNotifier',
|
||||
'Lorg/chromium/net/ProxyChangeListener',
|
||||
'Lorg/chromium/ui/gfx/NativeWindow',
|
||||
'Lorg/chromium/ui/SelectFileDialog',
|
||||
]
|
||||
if param == 'byte[][]':
|
||||
return '[[B'
|
||||
|
@ -17,7 +17,7 @@ import android.widget.TextView;
|
||||
|
||||
import org.chromium.base.CalledByNative;
|
||||
import org.chromium.content.app.AppResource;
|
||||
import org.chromium.content.browser.ContentViewCore;
|
||||
import org.chromium.ui.gfx.NativeWindow;
|
||||
|
||||
public class JavascriptAppModalDialog {
|
||||
private String mTitle;
|
||||
@ -60,10 +60,9 @@ public class JavascriptAppModalDialog {
|
||||
}
|
||||
|
||||
@CalledByNative
|
||||
void showJavascriptAppModalDialog(ContentViewCore contentViewCore, int nativeDialogPointer) {
|
||||
assert contentViewCore != null;
|
||||
|
||||
Context context = contentViewCore.getContext();
|
||||
void showJavascriptAppModalDialog(NativeWindow window, int nativeDialogPointer) {
|
||||
assert window != null;
|
||||
Context context = window.getActivity();
|
||||
|
||||
// Cache the native dialog pointer so that we can use it to return the
|
||||
// response.
|
||||
|
@ -52,9 +52,6 @@ class TabAndroid {
|
||||
const content::ContextMenuParams& params,
|
||||
const base::Callback<void(int)>& callback) = 0;
|
||||
|
||||
virtual void ShowSelectFileDialog(
|
||||
const base::android::ScopedJavaLocalRef<jobject>& select_file) = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Public methods that call to Java via JNI
|
||||
// --------------------------------------------------------------------------
|
||||
|
@ -409,6 +409,12 @@ void FileSelectHelper::RunFileChooserOnUIThread(
|
||||
gfx::NativeWindow owning_window =
|
||||
platform_util::GetTopLevel(render_view_host_->GetView()->GetNativeView());
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
// Android needs the original MIME types and an additional capture value.
|
||||
std::vector<string16> accept_types(params.accept_types);
|
||||
accept_types.push_back(params.capture);
|
||||
#endif
|
||||
|
||||
select_file_dialog_->SelectFile(
|
||||
dialog_type_,
|
||||
params.title,
|
||||
@ -419,7 +425,7 @@ void FileSelectHelper::RunFileChooserOnUIThread(
|
||||
FILE_PATH_LITERAL(""),
|
||||
owning_window,
|
||||
#if defined(OS_ANDROID)
|
||||
const_cast<content::FileChooserParams*>(¶ms));
|
||||
&accept_types);
|
||||
#else
|
||||
NULL);
|
||||
#endif
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "chrome/browser/platform_util.h"
|
||||
#include "content/public/browser/android/content_view_core.h"
|
||||
|
||||
namespace platform_util {
|
||||
|
||||
@ -23,7 +24,7 @@ void OpenExternal(const GURL& url) {
|
||||
|
||||
gfx::NativeWindow GetTopLevel(gfx::NativeView view) {
|
||||
NOTIMPLEMENTED();
|
||||
return view;
|
||||
return view->GetWindowAndroid();
|
||||
}
|
||||
|
||||
gfx::NativeView GetParent(gfx::NativeView view) {
|
||||
|
@ -10,17 +10,16 @@
|
||||
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
|
||||
#include "content/public/browser/android/content_view_core.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/common/javascript_message_type.h"
|
||||
#include "jni/JavascriptAppModalDialog_jni.h"
|
||||
#include "ui/gfx/android/window_android.h"
|
||||
|
||||
using base::android::AttachCurrentThread;
|
||||
using base::android::ConvertUTF16ToJavaString;
|
||||
using base::android::ScopedJavaLocalRef;
|
||||
using content::BrowserThread;
|
||||
using content::ContentViewCore;
|
||||
|
||||
// static
|
||||
NativeAppModalDialog* NativeAppModalDialog::CreateNativeJavaScriptPrompt(
|
||||
|
@ -1081,11 +1081,13 @@
|
||||
'../base/base.gyp:base',
|
||||
'../chrome/browser/component/components.gyp:web_contents_delegate_android_java',
|
||||
'../content/content.gyp:content_java',
|
||||
'../ui/ui.gyp:ui_java',
|
||||
],
|
||||
'export_dependent_settings': [
|
||||
'../base/base.gyp:base',
|
||||
'../chrome/browser/component/components.gyp:web_contents_delegate_android_java',
|
||||
'../content/content.gyp:content_java',
|
||||
'../ui/ui.gyp:ui_java',
|
||||
],
|
||||
'variables': {
|
||||
'package_name': 'chrome',
|
||||
|
@ -46,6 +46,7 @@ include_rules = [
|
||||
"+third_party/WebKit/Source/Platform/chromium",
|
||||
"+third_party/WebKit/Source/WebKit/chromium",
|
||||
|
||||
"+ui/android",
|
||||
# Aura is analogous to Win32 or a Gtk, so it is allowed.
|
||||
"+ui/aura",
|
||||
"+ui/base",
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "media/base/android/media_jni_registrar.h"
|
||||
#include "net/android/net_jni_registrar.h"
|
||||
#include "ui/android/ui_jni_registrar.h"
|
||||
#include "jni/LibraryLoader_jni.h"
|
||||
#include "ui/gfx/android/gfx_jni_registrar.h"
|
||||
|
||||
@ -66,6 +67,9 @@ static jboolean LibraryLoadedOnMainThread(JNIEnv* env, jclass clazz,
|
||||
if (!net::android::RegisterJni(env))
|
||||
return JNI_FALSE;
|
||||
|
||||
if (!ui::RegisterJni(env))
|
||||
return JNI_FALSE;
|
||||
|
||||
if (!content::android::RegisterCommonJni(env))
|
||||
return JNI_FALSE;
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/android/WebInputEventFactory.h"
|
||||
#include "ui/gfx/android/java_bitmap.h"
|
||||
#include "ui/gfx/android/window_android.h"
|
||||
#include "webkit/glue/webmenuitem.h"
|
||||
#include "webkit/user_agent/user_agent_util.h"
|
||||
|
||||
@ -79,11 +80,13 @@ ContentViewCore* ContentViewCore::GetNativeContentViewCore(JNIEnv* env,
|
||||
ContentViewCoreImpl::ContentViewCoreImpl(JNIEnv* env, jobject obj,
|
||||
bool hardware_accelerated,
|
||||
bool take_ownership_of_web_contents,
|
||||
WebContents* web_contents)
|
||||
WebContents* web_contents,
|
||||
ui::WindowAndroid* window_android)
|
||||
: java_ref_(env, obj),
|
||||
web_contents_(static_cast<WebContentsImpl*>(web_contents)),
|
||||
owns_web_contents_(take_ownership_of_web_contents),
|
||||
tab_crashed_(false) {
|
||||
tab_crashed_(false),
|
||||
window_android_(window_android) {
|
||||
DCHECK(web_contents) <<
|
||||
"A ContentViewCoreImpl should be created with a valid WebContents.";
|
||||
|
||||
@ -539,6 +542,10 @@ void ContentViewCoreImpl::LoadUrl(
|
||||
tab_crashed_ = false;
|
||||
}
|
||||
|
||||
ui::WindowAndroid* ContentViewCoreImpl::GetWindowAndroid() {
|
||||
return window_android_;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Native JNI methods
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -547,10 +554,12 @@ void ContentViewCoreImpl::LoadUrl(
|
||||
jint Init(JNIEnv* env, jobject obj,
|
||||
jboolean hardware_accelerated,
|
||||
jboolean take_ownership_of_web_contents,
|
||||
jint native_web_contents) {
|
||||
jint native_web_contents,
|
||||
jint native_window) {
|
||||
ContentViewCoreImpl* view = new ContentViewCoreImpl(
|
||||
env, obj, hardware_accelerated, take_ownership_of_web_contents,
|
||||
reinterpret_cast<WebContents*>(native_web_contents));
|
||||
reinterpret_cast<WebContents*>(native_web_contents),
|
||||
reinterpret_cast<ui::WindowAndroid*>(native_window));
|
||||
return reinterpret_cast<jint>(view);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,10 @@
|
||||
|
||||
struct WebMenuItem;
|
||||
|
||||
namespace ui {
|
||||
class WindowAndroid;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
class ContentViewClient;
|
||||
class RenderWidgetHostViewAndroid;
|
||||
@ -36,7 +40,8 @@ class ContentViewCoreImpl : public ContentViewCore,
|
||||
jobject obj,
|
||||
bool hardware_accelerated,
|
||||
bool take_ownership_of_web_contents,
|
||||
WebContents* web_contents);
|
||||
WebContents* web_contents,
|
||||
ui::WindowAndroid* window_android);
|
||||
|
||||
// ContentViewCore overrides
|
||||
virtual void Destroy(JNIEnv* env, jobject obj) OVERRIDE;
|
||||
@ -172,6 +177,7 @@ class ContentViewCoreImpl : public ContentViewCore,
|
||||
WebContents* web_contents() const { return web_contents_; }
|
||||
|
||||
virtual void LoadUrl(NavigationController::LoadURLParams& params) OVERRIDE;
|
||||
virtual ui::WindowAndroid* GetWindowAndroid() OVERRIDE;
|
||||
|
||||
private:
|
||||
// NotificationObserver implementation.
|
||||
@ -218,6 +224,9 @@ class ContentViewCoreImpl : public ContentViewCore,
|
||||
// Whether the renderer backing this ContentViewCore has crashed.
|
||||
bool tab_crashed_;
|
||||
|
||||
// The owning window that has a hold of main application activity.
|
||||
ui::WindowAndroid* window_android_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ContentViewCoreImpl);
|
||||
};
|
||||
|
||||
|
@ -79,7 +79,7 @@ gfx::NativeView WebContentsViewAndroid::GetContentNativeView() const {
|
||||
}
|
||||
|
||||
gfx::NativeWindow WebContentsViewAndroid::GetTopLevelNativeWindow() const {
|
||||
return content_view_core_;
|
||||
return content_view_core_->GetWindowAndroid();
|
||||
}
|
||||
|
||||
void WebContentsViewAndroid::GetContainerBounds(gfx::Rect* out) const {
|
||||
|
@ -282,12 +282,14 @@
|
||||
'dependencies': [
|
||||
'../base/base.gyp:base',
|
||||
'../net/net.gyp:net',
|
||||
'../ui/ui.gyp:ui_java',
|
||||
'common_aidl',
|
||||
'content_common',
|
||||
],
|
||||
'export_dependent_settings': [
|
||||
'../base/base.gyp:base',
|
||||
'../net/net.gyp:net',
|
||||
'../ui/ui.gyp:ui_java',
|
||||
],
|
||||
'variables': {
|
||||
'package_name': 'content',
|
||||
|
@ -603,6 +603,7 @@
|
||||
'../base/base.gyp:base_java',
|
||||
'../media/media.gyp:media_java',
|
||||
'../net/net.gyp:net_java',
|
||||
'../ui/ui.gyp:ui_java',
|
||||
],
|
||||
'actions': [
|
||||
{
|
||||
|
@ -20,6 +20,7 @@ import android.webkit.DownloadListener;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import org.chromium.content.browser.ContentViewCore;
|
||||
import org.chromium.ui.gfx.NativeWindow;
|
||||
|
||||
/**
|
||||
* The containing view for {@link ContentViewCore} that exists in the Android UI hierarchy and
|
||||
@ -96,12 +97,14 @@ public class ContentView extends FrameLayout implements ContentViewCore.Internal
|
||||
* @param context The Context the view is running in, through which it can
|
||||
* access the current theme, resources, etc.
|
||||
* @param nativeWebContents A pointer to the native web contents.
|
||||
* @param nativeWindow An instance of the NativeWindow.
|
||||
* @param personality One of {@link #PERSONALITY_CHROME} or {@link #PERSONALITY_VIEW}.
|
||||
* @return A ContentView instance.
|
||||
*/
|
||||
public static ContentView newInstance(Context context, int nativeWebContents, int personality) {
|
||||
return newInstance(context, nativeWebContents, null, android.R.attr.webViewStyle,
|
||||
personality);
|
||||
public static ContentView newInstance(Context context, int nativeWebContents,
|
||||
NativeWindow nativeWindow, int personality) {
|
||||
return newInstance(context, nativeWebContents, nativeWindow, null,
|
||||
android.R.attr.webViewStyle, personality);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,14 +112,16 @@ public class ContentView extends FrameLayout implements ContentViewCore.Internal
|
||||
* @param context The Context the view is running in, through which it can
|
||||
* access the current theme, resources, etc.
|
||||
* @param nativeWebContents A pointer to the native web contents.
|
||||
* @param nativeWindow An instance of the NativeWindow.
|
||||
* @param attrs The attributes of the XML tag that is inflating the view.
|
||||
* @return A ContentView instance.
|
||||
*/
|
||||
public static ContentView newInstance(Context context, int nativeWebContents,
|
||||
AttributeSet attrs) {
|
||||
NativeWindow nativeWindow, AttributeSet attrs) {
|
||||
// TODO(klobag): use the WebViewStyle as the default style for now. It enables scrollbar.
|
||||
// When ContentView is moved to framework, we can define its own style in the res.
|
||||
return newInstance(context, nativeWebContents, attrs, android.R.attr.webViewStyle);
|
||||
return newInstance(context, nativeWebContents, nativeWindow, attrs,
|
||||
android.R.attr.webViewStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,31 +129,34 @@ public class ContentView extends FrameLayout implements ContentViewCore.Internal
|
||||
* @param context The Context the view is running in, through which it can
|
||||
* access the current theme, resources, etc.
|
||||
* @param nativeWebContents A pointer to the native web contents.
|
||||
* @param nativeWindow An instance of the NativeWindow.
|
||||
* @param attrs The attributes of the XML tag that is inflating the view.
|
||||
* @param defStyle The default style to apply to this view.
|
||||
* @return A ContentView instance.
|
||||
*/
|
||||
public static ContentView newInstance(Context context, int nativeWebContents,
|
||||
AttributeSet attrs, int defStyle) {
|
||||
return newInstance(context, nativeWebContents, attrs, defStyle, PERSONALITY_VIEW);
|
||||
NativeWindow nativeWindow, AttributeSet attrs, int defStyle) {
|
||||
return newInstance(context, nativeWebContents, nativeWindow, attrs, defStyle,
|
||||
PERSONALITY_VIEW);
|
||||
}
|
||||
|
||||
private static ContentView newInstance(Context context, int nativeWebContents,
|
||||
AttributeSet attrs, int defStyle, int personality) {
|
||||
NativeWindow nativeWindow, AttributeSet attrs, int defStyle, int personality) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
||||
return new ContentView(context, nativeWebContents, attrs, defStyle, personality);
|
||||
} else {
|
||||
return new JellyBeanContentView(context, nativeWebContents, attrs, defStyle,
|
||||
return new ContentView(context, nativeWebContents, nativeWindow, attrs, defStyle,
|
||||
personality);
|
||||
} else {
|
||||
return new JellyBeanContentView(context, nativeWebContents, nativeWindow, attrs,
|
||||
defStyle, personality);
|
||||
}
|
||||
}
|
||||
|
||||
protected ContentView(Context context, int nativeWebContents, AttributeSet attrs, int defStyle,
|
||||
int personality) {
|
||||
protected ContentView(Context context, int nativeWebContents, NativeWindow nativeWindow,
|
||||
AttributeSet attrs, int defStyle, int personality) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
mContentViewCore = new ContentViewCore(context, personality);
|
||||
mContentViewCore.initialize(this, this, true, nativeWebContents, false);
|
||||
mContentViewCore.initialize(this, this, true, nativeWebContents, nativeWindow, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,6 +35,7 @@ import org.chromium.content.browser.TouchPoint;
|
||||
import org.chromium.content.browser.ZoomManager;
|
||||
import org.chromium.content.common.CleanupReference;
|
||||
import org.chromium.content.common.TraceEvent;
|
||||
import org.chromium.ui.gfx.NativeWindow;
|
||||
|
||||
/**
|
||||
* Provides a Java-side 'wrapper' around a WebContent (native) instance.
|
||||
@ -311,6 +312,7 @@ public class ContentViewCore implements MotionEventDelegate {
|
||||
* @param takeOwnershipOfWebContents Whether this object will take ownership of
|
||||
* nativeWebContents over on its native side.
|
||||
* @param nativeWebContents A pointer to the native web contents.
|
||||
* @param nativeWindow An instance of the NativeWindow.
|
||||
* @param isAccessFromFileURLsGrantedByDefault Default WebSettings configuration.
|
||||
*/
|
||||
// Perform important post-construction set up of the ContentViewCore.
|
||||
@ -321,11 +323,11 @@ public class ContentViewCore implements MotionEventDelegate {
|
||||
// We supply the nativeWebContents pointer here rather than in the constructor to allow us
|
||||
// to set the private browsing mode at a later point for the WebView implementation.
|
||||
public void initialize(ViewGroup containerView, InternalAccessDelegate internalDispatcher,
|
||||
boolean takeOwnershipOfWebContents, int nativeWebContents,
|
||||
boolean takeOwnershipOfWebContents, int nativeWebContents, NativeWindow nativeWindow,
|
||||
boolean isAccessFromFileURLsGrantedByDefault) {
|
||||
mContainerView = containerView;
|
||||
mNativeContentViewCore = nativeInit(mHardwareAccelerated, takeOwnershipOfWebContents,
|
||||
nativeWebContents);
|
||||
nativeWebContents, nativeWindow.getNativePointer());
|
||||
mCleanupReference = new CleanupReference(
|
||||
this, new DestroyRunnable(mNativeContentViewCore));
|
||||
mContentSettings = new ContentSettings(
|
||||
@ -1327,7 +1329,7 @@ public class ContentViewCore implements MotionEventDelegate {
|
||||
// The following methods are implemented at native side.
|
||||
|
||||
private native int nativeInit(boolean hardwareAccelerated, boolean takeOwnershipOfWebContents,
|
||||
int webContentsPtr);
|
||||
int webContentsPtr, int windowAndroidPtr);
|
||||
|
||||
private static native void nativeDestroy(int nativeContentViewCore);
|
||||
|
||||
|
@ -10,13 +10,15 @@ import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import org.chromium.ui.gfx.NativeWindow;
|
||||
|
||||
/**
|
||||
* A version of {@link ContentView} that supports JellyBean features.
|
||||
*/
|
||||
class JellyBeanContentView extends ContentView {
|
||||
JellyBeanContentView(Context context, int nativeWebContents, AttributeSet attrs, int defStyle,
|
||||
int personality) {
|
||||
super(context, nativeWebContents, attrs, defStyle, personality);
|
||||
JellyBeanContentView(Context context, int nativeWebContents, NativeWindow nativeWindow,
|
||||
AttributeSet attrs, int defStyle, int personality) {
|
||||
super(context, nativeWebContents, nativeWindow, attrs, defStyle, personality);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5,10 +5,15 @@
|
||||
#ifndef CONTENT_PUBLIC_BROWSER_ANDROID_CONTENT_VIEW_CORE_H_
|
||||
#define CONTENT_PUBLIC_BROWSER_ANDROID_CONTENT_VIEW_CORE_H_
|
||||
|
||||
#include "base/android/scoped_java_ref.h"
|
||||
#include <jni.h>
|
||||
|
||||
class GURL;
|
||||
|
||||
namespace ui {
|
||||
class WindowAndroid;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
|
||||
class WebContents;
|
||||
@ -49,6 +54,7 @@ class ContentViewCore {
|
||||
|
||||
virtual base::android::ScopedJavaLocalRef<jobject> GetJavaObject() = 0;
|
||||
|
||||
virtual ui::WindowAndroid* GetWindowAndroid() = 0;
|
||||
protected:
|
||||
virtual ~ContentViewCore() {};
|
||||
};
|
||||
|
@ -15,6 +15,7 @@ import org.chromium.content.app.AppResource;
|
||||
import org.chromium.content.app.LibraryLoader;
|
||||
import org.chromium.content.browser.ContentView;
|
||||
import org.chromium.content.common.CommandLine;
|
||||
import org.chromium.ui.gfx.NativeWindow;
|
||||
|
||||
/**
|
||||
* Activity for managing the Content Shell.
|
||||
@ -42,6 +43,7 @@ public class ContentShellActivity extends Activity {
|
||||
|
||||
setContentView(R.layout.content_shell_activity);
|
||||
mShellManager = (ShellManager) findViewById(R.id.shell_container);
|
||||
mShellManager.setWindow(new NativeWindow(this));
|
||||
|
||||
String startupUrl = getUrlFromIntent(getIntent());
|
||||
if (!TextUtils.isEmpty(startupUrl)) {
|
||||
|
@ -23,6 +23,7 @@ import org.chromium.base.CalledByNative;
|
||||
import org.chromium.base.JNINamespace;
|
||||
import org.chromium.content.browser.ContentView;
|
||||
import org.chromium.content.browser.LoadUrlParams;
|
||||
import org.chromium.ui.gfx.NativeWindow;
|
||||
|
||||
/**
|
||||
* Container for the various UI components that make up a shell window.
|
||||
@ -48,6 +49,7 @@ public class Shell extends LinearLayout {
|
||||
private ClipDrawable mProgressDrawable;
|
||||
|
||||
private View mSurfaceView;
|
||||
private NativeWindow mWindow;
|
||||
|
||||
/**
|
||||
* Constructor for inflating via XML.
|
||||
@ -67,6 +69,13 @@ public class Shell extends LinearLayout {
|
||||
FrameLayout.LayoutParams.MATCH_PARENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param window The owning window for this shell.
|
||||
*/
|
||||
public void setWindow(NativeWindow window) {
|
||||
mWindow = window;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
@ -173,7 +182,7 @@ public class Shell extends LinearLayout {
|
||||
@CalledByNative
|
||||
private void initFromNativeTabContents(int nativeTabContents) {
|
||||
mContentView = ContentView.newInstance(
|
||||
getContext(), nativeTabContents, ContentView.PERSONALITY_CHROME);
|
||||
getContext(), nativeTabContents, mWindow, ContentView.PERSONALITY_CHROME);
|
||||
if (mContentView.getUrl() != null) mUrlTextView.setText(mContentView.getUrl());
|
||||
((FrameLayout) findViewById(R.id.contentview_holder)).addView(mContentView,
|
||||
new FrameLayout.LayoutParams(
|
||||
|
@ -14,6 +14,7 @@ import android.widget.FrameLayout;
|
||||
|
||||
import org.chromium.base.CalledByNative;
|
||||
import org.chromium.base.JNINamespace;
|
||||
import org.chromium.ui.gfx.NativeWindow;
|
||||
|
||||
/**
|
||||
* Container and generator of ShellViews.
|
||||
@ -21,6 +22,7 @@ import org.chromium.base.JNINamespace;
|
||||
@JNINamespace("content")
|
||||
public class ShellManager extends FrameLayout {
|
||||
|
||||
private NativeWindow mWindow;
|
||||
private Shell mActiveShell;
|
||||
|
||||
private String mStartupUrl = ContentShellActivity.DEFAULT_SHELL_URL;
|
||||
@ -55,6 +57,13 @@ public class ShellManager extends FrameLayout {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param window The window used to generate all shells.
|
||||
*/
|
||||
public void setWindow(NativeWindow window) {
|
||||
mWindow = window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the startup URL for new shell windows.
|
||||
*/
|
||||
@ -84,6 +93,7 @@ public class ShellManager extends FrameLayout {
|
||||
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
Shell shellView = (Shell) inflater.inflate(R.layout.shell_view, null);
|
||||
shellView.setSurfaceView(mSurfaceView);
|
||||
shellView.setWindow(mWindow);
|
||||
|
||||
removeAllViews();
|
||||
if (mActiveShell != null && mActiveShell.getContentView() != null) {
|
||||
|
1
ui/DEPS
1
ui/DEPS
@ -4,6 +4,7 @@ include_rules = [
|
||||
"+grit/native_theme_resources.h",
|
||||
"+grit/ui_resources.h",
|
||||
"+grit/ui_strings.h",
|
||||
"+jni",
|
||||
"+net",
|
||||
"+skia",
|
||||
"+third_party/mozilla",
|
||||
|
257
ui/android/java/src/org/chromium/ui/SelectFileDialog.java
Normal file
257
ui/android/java/src/org/chromium/ui/SelectFileDialog.java
Normal file
@ -0,0 +1,257 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package org.chromium.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.chromium.base.CalledByNative;
|
||||
import org.chromium.base.JNINamespace;
|
||||
import org.chromium.ui.gfx.NativeWindow;
|
||||
|
||||
/**
|
||||
* A dialog that is triggered from a file input field that allows a user to select a file based on
|
||||
* a set of accepted file types. The path of the selected file is passed to the native dialog.
|
||||
*/
|
||||
@JNINamespace("ui")
|
||||
class SelectFileDialog implements NativeWindow.IntentCallback{
|
||||
// TODO (aurimas): Swap these constants with AppResources when it gets moved to base to support
|
||||
// internationalization.
|
||||
private static final String LOW_MEMORY_ERROR =
|
||||
"Unable to complete previous operation due to low memory";
|
||||
private static final String OPENING_FILE_ERROR = "Failed to open selected file";
|
||||
|
||||
private static final String IMAGE_TYPE = "image/";
|
||||
private static final String VIDEO_TYPE = "video/";
|
||||
private static final String AUDIO_TYPE = "audio/";
|
||||
private static final String ALL_IMAGE_TYPES = IMAGE_TYPE + "*";
|
||||
private static final String ALL_VIDEO_TYPES = VIDEO_TYPE + "*";
|
||||
private static final String ALL_AUDIO_TYPES = AUDIO_TYPE + "*";
|
||||
private static final String ANY_TYPES = "*/*";
|
||||
private static final String CAPTURE_CAMERA = "camera";
|
||||
private static final String CAPTURE_CAMCORDER = "camcorder";
|
||||
private static final String CAPTURE_MICROPHONE = "microphone";
|
||||
private static final String CAPTURE_FILESYSTEM = "filesystem";
|
||||
private static final String CAPTURE_IMAGE_DIRECTORY = "browser-photos";
|
||||
|
||||
private final int mNativeSelectFileDialog;
|
||||
private List<String> mFileTypes;
|
||||
private String mCapture; // May be null if no capture parameter was set.
|
||||
private Uri mCameraOutputUri;
|
||||
|
||||
private SelectFileDialog(int nativeSelectFileDialog) {
|
||||
mNativeSelectFileDialog = nativeSelectFileDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and starts an intent based on the passed fileTypes and capture value.
|
||||
* @param fileTypes MIME types requested (i.e. "image/*")
|
||||
* @param capture The capture value as described in http://www.w3.org/TR/html-media-capture/
|
||||
* @param window The NativeWindow that can show intents
|
||||
*/
|
||||
@CalledByNative
|
||||
private void selectFile(String[] fileTypes, String capture, NativeWindow window) {
|
||||
mFileTypes = new ArrayList<String>(Arrays.asList(fileTypes));
|
||||
mCapture = capture;
|
||||
|
||||
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
|
||||
Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
mCameraOutputUri = Uri.fromFile(getFileForImageCapture());
|
||||
camera.putExtra(MediaStore.EXTRA_OUTPUT, mCameraOutputUri);
|
||||
Intent camcorder = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
|
||||
Intent soundRecorder = new Intent(
|
||||
MediaStore.Audio.Media.RECORD_SOUND_ACTION);
|
||||
|
||||
// Quick check - if a capture parameter other than filesystem (the default) is specified we
|
||||
// should just launch the appropriate intent. Otherwise build up a chooser based on the
|
||||
// accept type and then display that to the user.
|
||||
if (captureCamera()) {
|
||||
if (window.showIntent(camera, this, LOW_MEMORY_ERROR)) return;
|
||||
} else if (captureCamcorder()) {
|
||||
if (window.showIntent(camcorder, this, LOW_MEMORY_ERROR)) return;
|
||||
} else if (captureMicrophone()) {
|
||||
if (window.showIntent(soundRecorder, this, LOW_MEMORY_ERROR)) return;
|
||||
}
|
||||
|
||||
Intent getContentIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
getContentIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
ArrayList<Intent> extraIntents = new ArrayList<Intent>();
|
||||
if (!noSpecificType()) {
|
||||
// Create a chooser based on the accept type that was specified in the webpage. Note
|
||||
// that if the web page specified multiple accept types, we will have built a generic
|
||||
// chooser above.
|
||||
if (shouldShowImageTypes()) {
|
||||
extraIntents.add(camera);
|
||||
getContentIntent.setType("image/*");
|
||||
} else if (shouldShowVideoTypes()) {
|
||||
extraIntents.add(camcorder);
|
||||
getContentIntent.setType("video/*");
|
||||
} else if (shouldShowAudioTypes()) {
|
||||
extraIntents.add(soundRecorder);
|
||||
getContentIntent.setType("audio/*");
|
||||
}
|
||||
}
|
||||
|
||||
if (extraIntents.isEmpty()) {
|
||||
// We couldn't resolve an accept type, so fallback to a generic chooser.
|
||||
getContentIntent.setType("*/*");
|
||||
extraIntents.add(camera);
|
||||
extraIntents.add(camcorder);
|
||||
extraIntents.add(soundRecorder);
|
||||
}
|
||||
|
||||
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS,
|
||||
extraIntents.toArray(new Intent[] { }));
|
||||
|
||||
chooser.putExtra(Intent.EXTRA_INTENT, getContentIntent);
|
||||
|
||||
if (!window.showIntent(chooser, this, LOW_MEMORY_ERROR)) onFileNotSelected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a file for the image capture in the CAPTURE_IMAGE_DIRECTORY directory.
|
||||
*/
|
||||
private File getFileForImageCapture() {
|
||||
File externalDataDir = Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_DCIM);
|
||||
File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
|
||||
File.separator + CAPTURE_IMAGE_DIRECTORY);
|
||||
if (!cameraDataDir.exists() && !cameraDataDir.mkdirs()) {
|
||||
cameraDataDir = externalDataDir;
|
||||
}
|
||||
File photoFile = new File(cameraDataDir.getAbsolutePath() +
|
||||
File.separator + System.currentTimeMillis() + ".jpg");
|
||||
return photoFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method to handle the intent results and pass on the path to the native
|
||||
* SelectFileDialog.
|
||||
* @param window The window that has access to the application activity.
|
||||
* @param resultCode The result code whether the intent returned successfully.
|
||||
* @param contentResolver The content resolver used to extract the path of the selected file.
|
||||
* @param results The results of the requested intent.
|
||||
*/
|
||||
@Override
|
||||
public void onIntentCompleted(NativeWindow window, int resultCode,
|
||||
ContentResolver contentResolver, Intent results) {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
onFileNotSelected();
|
||||
return;
|
||||
}
|
||||
boolean success = false;
|
||||
if (results == null) {
|
||||
// If we have a successful return but no data, then assume this is the camera returning
|
||||
// the photo that we requested.
|
||||
nativeOnFileSelected(mNativeSelectFileDialog, mCameraOutputUri.getPath());
|
||||
success = true;
|
||||
|
||||
// Broadcast to the media scanner that there's a new photo on the device so it will
|
||||
// show up right away in the gallery (rather than waiting until the next time the media
|
||||
// scanner runs).
|
||||
window.getActivity().sendBroadcast(new Intent(
|
||||
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mCameraOutputUri));
|
||||
} else {
|
||||
// We get back a content:// URI from the system if the user picked a file from the
|
||||
// gallery. The ContentView has functionality that will convert that content:// URI to
|
||||
// a file path on disk that Chromium understands.
|
||||
Cursor c = contentResolver.query(results.getData(),
|
||||
new String[] { MediaStore.MediaColumns.DATA }, null, null, null);
|
||||
if (c != null) {
|
||||
if (c.getCount() == 1) {
|
||||
c.moveToFirst();
|
||||
String path = c.getString(0);
|
||||
if (path != null) {
|
||||
// Not all providers support the MediaStore.DATA column. For example,
|
||||
// Gallery3D (com.android.gallery3d.provider) does not support it for
|
||||
// Picasa Web Album images.
|
||||
nativeOnFileSelected(mNativeSelectFileDialog, path);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
if (!success) {
|
||||
onFileNotSelected();
|
||||
window.showError(OPENING_FILE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
private void onFileNotSelected() {
|
||||
nativeOnFileNotSelected(mNativeSelectFileDialog);
|
||||
}
|
||||
|
||||
private boolean noSpecificType() {
|
||||
// We use a single Intent to decide the type of the file chooser we display to the user,
|
||||
// which means we can only give it a single type. If there are multiple accept types
|
||||
// specified, we will fallback to a generic chooser (unless a capture parameter has been
|
||||
// specified, in which case we'll try to satisfy that first.
|
||||
return mFileTypes.size() != 1 || mFileTypes.contains(ANY_TYPES);
|
||||
}
|
||||
|
||||
private boolean shouldShowTypes(String allTypes, String specificType) {
|
||||
if (noSpecificType() || mFileTypes.contains(allTypes)) return true;
|
||||
return acceptSpecificType(specificType);
|
||||
}
|
||||
|
||||
private boolean shouldShowImageTypes() {
|
||||
return shouldShowTypes(ALL_IMAGE_TYPES,IMAGE_TYPE);
|
||||
}
|
||||
|
||||
private boolean shouldShowVideoTypes() {
|
||||
return shouldShowTypes(ALL_VIDEO_TYPES, VIDEO_TYPE);
|
||||
}
|
||||
|
||||
private boolean shouldShowAudioTypes() {
|
||||
return shouldShowTypes(ALL_AUDIO_TYPES, AUDIO_TYPE);
|
||||
}
|
||||
|
||||
private boolean captureCamera() {
|
||||
return shouldShowImageTypes() && mCapture != null && mCapture.startsWith(CAPTURE_CAMERA);
|
||||
}
|
||||
|
||||
private boolean captureCamcorder() {
|
||||
return shouldShowVideoTypes() && mCapture != null &&
|
||||
mCapture.startsWith(CAPTURE_CAMCORDER);
|
||||
}
|
||||
|
||||
private boolean captureMicrophone() {
|
||||
return shouldShowAudioTypes() && mCapture != null &&
|
||||
mCapture.startsWith(CAPTURE_MICROPHONE);
|
||||
}
|
||||
|
||||
private boolean captureFilesystem() {
|
||||
return mCapture != null && mCapture.startsWith(CAPTURE_FILESYSTEM);
|
||||
}
|
||||
|
||||
private boolean acceptSpecificType(String accept) {
|
||||
for (String type : mFileTypes) {
|
||||
if (type.startsWith(accept)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@CalledByNative
|
||||
private static SelectFileDialog create(int nativeSelectFileDialog) {
|
||||
return new SelectFileDialog(nativeSelectFileDialog);
|
||||
}
|
||||
|
||||
private native void nativeOnFileSelected(int nativeSelectFileDialogImpl,
|
||||
String filePath);
|
||||
private native void nativeOnFileNotSelected(int nativeSelectFileDialogImpl);
|
||||
}
|
226
ui/android/java/src/org/chromium/ui/gfx/NativeWindow.java
Normal file
226
ui/android/java/src/org/chromium/ui/gfx/NativeWindow.java
Normal file
@ -0,0 +1,226 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package org.chromium.ui.gfx;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.util.SparseArray;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.chromium.base.JNINamespace;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* The window that has access to the main activity and is able to create and receive intents,
|
||||
* and show error messages.
|
||||
*/
|
||||
@JNINamespace("ui")
|
||||
public class NativeWindow {
|
||||
|
||||
// Constants used for intent request code bounding.
|
||||
private static final int REQUEST_CODE_PREFIX = 1000;
|
||||
private static final int REQUEST_CODE_RANGE_SIZE = 100;
|
||||
// A string used as a key to store intent errors in a bundle
|
||||
static final String WINDOW_CALLBACK_ERRORS = "window_callback_errors";
|
||||
|
||||
// Native pointer to the c++ WindowAndroid object.
|
||||
private int mNativeWindowAndroid = 0;
|
||||
private int mNextRequestCode = 0;
|
||||
protected Activity mActivity;
|
||||
private SparseArray<IntentCallback> mOutstandingIntents;
|
||||
private HashMap<Integer, String> mIntentErrors;
|
||||
|
||||
/**
|
||||
* An interface that intent callback objects have to implement.
|
||||
*/
|
||||
public interface IntentCallback {
|
||||
/**
|
||||
* Handles the data returned by the requested intent.
|
||||
* @param window A window reference.
|
||||
* @param resultCode Result code of the requested intent.
|
||||
* @param contentResolver An instance of ContentResolver class for accessing returned data.
|
||||
* @param data The data returned by the intent.
|
||||
*/
|
||||
public void onIntentCompleted(NativeWindow window, int resultCode,
|
||||
ContentResolver contentResolver, Intent data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Window object, saves a reference to the main activity, and initializes the
|
||||
* outstanding intent map. NativeWindowAndroid gets lazily loaded on getNativePointer().
|
||||
* @param activity The main application activity.
|
||||
*/
|
||||
public NativeWindow(Activity activity) {
|
||||
mActivity = activity;
|
||||
mOutstandingIntents = new SparseArray<IntentCallback>();
|
||||
mIntentErrors = new HashMap<Integer, String>();
|
||||
mNativeWindowAndroid = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the c++ WindowAndroid object if one has been created.
|
||||
*/
|
||||
public void destroy() {
|
||||
if (mNativeWindowAndroid != 0) {
|
||||
nativeDestroy(mNativeWindowAndroid);
|
||||
mNativeWindowAndroid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an intent and returns the results to the callback object.
|
||||
* @param intent The intent that needs to be showed.
|
||||
* @param callback The object that will receive the results for the intent.
|
||||
* @return Whether the intent was shown.
|
||||
*/
|
||||
public boolean showIntent(Intent intent, IntentCallback callback) {
|
||||
return showIntent(intent, callback, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an intent and returns the results to the callback object.
|
||||
* @param intent The intent that needs to be showed.
|
||||
* @param callback The object that will receive the results for the intent.
|
||||
* @param errorId The id of the error string to be show if activity is paused before intent
|
||||
* results.
|
||||
* @return Whether the intent was shown.
|
||||
*/
|
||||
public boolean showIntent(Intent intent, IntentCallback callback, int errorId) {
|
||||
String error = null;
|
||||
try {
|
||||
error = mActivity.getString(errorId);
|
||||
} catch (Resources.NotFoundException e) { }
|
||||
return showIntent(intent, callback, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an intent and returns the results to the callback object.
|
||||
* @param intent The intent that needs to be showed.
|
||||
* @param callback The object that will receive the results for the intent.
|
||||
* @param error The error string to be show if activity is paused before intent results.
|
||||
* @return Whether the intent was shown.
|
||||
*/
|
||||
public boolean showIntent(Intent intent, IntentCallback callback, String error) {
|
||||
int requestCode = REQUEST_CODE_PREFIX + mNextRequestCode;
|
||||
mNextRequestCode = (mNextRequestCode + 1) % REQUEST_CODE_RANGE_SIZE;
|
||||
|
||||
try {
|
||||
mActivity.startActivityForResult(intent, requestCode);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mOutstandingIntents.put(requestCode, callback);
|
||||
if (error != null) mIntentErrors.put(requestCode, error);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the error messages that should be shown if any pending intents would return
|
||||
* after the application has been put onPause.
|
||||
* @param bundle The bundle to save the information in onPause
|
||||
*/
|
||||
public void saveInstanceState(Bundle bundle) {
|
||||
bundle.putSerializable(WINDOW_CALLBACK_ERRORS, mIntentErrors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the error messages that should be shown if any pending intents would return
|
||||
* after the application has been put onPause.
|
||||
* @param bundle The bundle to restore the information from onResume
|
||||
*/
|
||||
public void restoreInstanceState(Bundle bundle) {
|
||||
if (bundle == null) return;
|
||||
|
||||
Object errors = bundle.getSerializable(WINDOW_CALLBACK_ERRORS);
|
||||
if (errors instanceof HashMap) {
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<Integer, String> intentErrors = (HashMap<Integer, String>) errors;
|
||||
mIntentErrors = intentErrors;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays an error message with a provided error message string.
|
||||
* @param error The error message string to be displayed.
|
||||
*/
|
||||
public void showError(String error) {
|
||||
if (error != null) Toast.makeText(mActivity, error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays an error message with a provided error message string id.
|
||||
* @param errorId The string id of the error message string to be displayed.
|
||||
*/
|
||||
public void showError(int errorId) {
|
||||
String error = null;
|
||||
try {
|
||||
error = mActivity.getString(errorId);
|
||||
} catch (Resources.NotFoundException e) { }
|
||||
showError(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays an error message for a nonexistent callback.
|
||||
* @param error The error message string to be displayed.
|
||||
*/
|
||||
protected void showCallbackNonExistentError(String error) {
|
||||
showError(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The main application activity.
|
||||
*/
|
||||
public Activity getActivity() {
|
||||
return mActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
String errorMessage = mIntentErrors.remove(requestCode);
|
||||
|
||||
if (callback != null) {
|
||||
callback.onIntentCompleted(this, resultCode,
|
||||
mActivity.getContentResolver(), data);
|
||||
return true;
|
||||
} else {
|
||||
if (errorMessage != null) {
|
||||
showCallbackNonExistentError(errorMessage);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the c++ AndroidWindow object and calls the initializer if
|
||||
* the object has not been previously initialized.
|
||||
* @return A pointer to the c++ AndroidWindow.
|
||||
*/
|
||||
public int getNativePointer() {
|
||||
if (mNativeWindowAndroid == 0) {
|
||||
mNativeWindowAndroid = nativeInit();
|
||||
}
|
||||
return mNativeWindowAndroid;
|
||||
}
|
||||
|
||||
private native int nativeInit();
|
||||
private native void nativeDestroy(int nativeWindowAndroid);
|
||||
|
||||
}
|
24
ui/android/ui_jni_registrar.cc
Normal file
24
ui/android/ui_jni_registrar.cc
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ui/android/ui_jni_registrar.h"
|
||||
|
||||
#include "base/android/jni_android.h"
|
||||
#include "base/android/jni_registrar.h"
|
||||
#include "ui/base/dialogs/select_file_dialog_android.h"
|
||||
#include "ui/gfx/android/window_android.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
static base::android::RegistrationMethod kUiRegisteredMethods[] = {
|
||||
{ "NativeWindow", WindowAndroid::RegisterWindowAndroid },
|
||||
{ "SelectFileDialog", SelectFileDialogImpl::RegisterSelectFileDialog },
|
||||
};
|
||||
|
||||
bool RegisterJni(JNIEnv* env) {
|
||||
return RegisterNativeMethods(env, kUiRegisteredMethods,
|
||||
arraysize(kUiRegisteredMethods));
|
||||
}
|
||||
|
||||
} // namespace ui
|
17
ui/android/ui_jni_registrar.h
Normal file
17
ui/android/ui_jni_registrar.h
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef UI_ANDROID_UI_JNI_REGISTRAR_H_
|
||||
#define UI_ANDROID_UI_JNI_REGISTRAR_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
namespace ui {
|
||||
|
||||
// Register all JNI bindings necessary for chrome.
|
||||
bool RegisterJni(JNIEnv* env);
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif // UI_ANDROID_UI_JNI_REGISTRAR_H_
|
@ -20,6 +20,8 @@
|
||||
#include "ui/base/dialogs/select_file_dialog_mac.h"
|
||||
#elif defined(TOOLKIT_GTK)
|
||||
#include "ui/base/dialogs/gtk/select_file_dialog_impl.h"
|
||||
#elif defined(OS_ANDROID)
|
||||
#include "ui/base/dialogs/select_file_dialog_android.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
@ -84,8 +86,7 @@ SelectFileDialog* SelectFileDialog::Create(Listener* listener,
|
||||
#elif defined(TOOLKIT_GTK)
|
||||
return CreateLinuxSelectFileDialog(listener, policy);
|
||||
#elif defined(OS_ANDROID)
|
||||
// see crbug.com/116131 to track implemenation of SelectFileDialog
|
||||
NOTIMPLEMENTED();
|
||||
return CreateAndroidSelectFileDialog(listener, policy);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
|
113
ui/base/dialogs/select_file_dialog_android.cc
Normal file
113
ui/base/dialogs/select_file_dialog_android.cc
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "select_file_dialog_android.h"
|
||||
|
||||
#include "base/android/jni_android.h"
|
||||
#include "base/android/jni_string.h"
|
||||
#include "base/android/jni_array.h"
|
||||
#include "base/android/scoped_java_ref.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/string_split.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "jni/SelectFileDialog_jni.h"
|
||||
#include "ui/gfx/android/window_android.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
// static
|
||||
SelectFileDialogImpl* SelectFileDialogImpl::Create(Listener* listener,
|
||||
ui::SelectFilePolicy* policy) {
|
||||
return new SelectFileDialogImpl(listener, policy);
|
||||
}
|
||||
|
||||
void SelectFileDialogImpl::OnFileSelected(JNIEnv* env,
|
||||
jobject java_object,
|
||||
jstring filepath) {
|
||||
if (listener_) {
|
||||
std::string path = base::android::ConvertJavaStringToUTF8(env, filepath);
|
||||
listener_->FileSelected(FilePath(path), 0, NULL);
|
||||
}
|
||||
|
||||
is_running_ = false;
|
||||
}
|
||||
|
||||
void SelectFileDialogImpl::OnFileNotSelected(
|
||||
JNIEnv* env,
|
||||
jobject java_object) {
|
||||
if (listener_)
|
||||
listener_->FileSelectionCanceled(NULL);
|
||||
|
||||
is_running_ = false;
|
||||
}
|
||||
|
||||
bool SelectFileDialogImpl::IsRunning(gfx::NativeWindow) const {
|
||||
return is_running_;
|
||||
}
|
||||
|
||||
void SelectFileDialogImpl::ListenerDestroyed() {
|
||||
listener_ = NULL;
|
||||
}
|
||||
|
||||
void SelectFileDialogImpl::SelectFileImpl(
|
||||
ui::SelectFileDialog::Type type,
|
||||
const string16& title,
|
||||
const FilePath& default_path,
|
||||
const SelectFileDialog::FileTypeInfo* file_types,
|
||||
int file_type_index,
|
||||
const std::string& default_extension,
|
||||
gfx::NativeWindow owning_window,
|
||||
void* params) {
|
||||
JNIEnv* env = base::android::AttachCurrentThread();
|
||||
|
||||
std::vector<string16> accept_types =
|
||||
*(reinterpret_cast<std::vector<string16>*>(params));
|
||||
|
||||
// The last string in params is expected to be the string with capture value.
|
||||
ScopedJavaLocalRef<jstring> capture_value =
|
||||
base::android::ConvertUTF16ToJavaString(env,
|
||||
StringToLowerASCII(accept_types.back()));
|
||||
base::android::CheckException(env);
|
||||
accept_types.pop_back();
|
||||
|
||||
// The rest params elements are expected to be accept_types.
|
||||
ScopedJavaLocalRef<jobjectArray> accept_types_java =
|
||||
base::android::ToJavaArrayOfStrings(env, accept_types);
|
||||
|
||||
Java_SelectFileDialog_selectFile(env, java_object_.obj(),
|
||||
accept_types_java.obj(),
|
||||
capture_value.obj(),
|
||||
owning_window->GetJavaObject().obj());
|
||||
is_running_ = true;
|
||||
}
|
||||
|
||||
bool SelectFileDialogImpl::RegisterSelectFileDialog(JNIEnv* env) {
|
||||
return RegisterNativesImpl(env);
|
||||
}
|
||||
|
||||
SelectFileDialogImpl::~SelectFileDialogImpl() {
|
||||
}
|
||||
|
||||
SelectFileDialogImpl::SelectFileDialogImpl(Listener* listener,
|
||||
ui::SelectFilePolicy* policy)
|
||||
: ui::SelectFileDialog(listener, policy),
|
||||
is_running_(false) {
|
||||
JNIEnv* env = base::android::AttachCurrentThread();
|
||||
java_object_.Reset(
|
||||
Java_SelectFileDialog_create(env, reinterpret_cast<jint>(this)));
|
||||
}
|
||||
|
||||
bool SelectFileDialogImpl::HasMultipleFileTypeChoicesImpl() {
|
||||
NOTIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
SelectFileDialog* CreateAndroidSelectFileDialog(
|
||||
SelectFileDialog::Listener* listener,
|
||||
SelectFilePolicy* policy) {
|
||||
return SelectFileDialogImpl::Create(listener, policy);
|
||||
}
|
||||
|
||||
} // namespace ui
|
66
ui/base/dialogs/select_file_dialog_android.h
Normal file
66
ui/base/dialogs/select_file_dialog_android.h
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef UI_BASE_DIALOGS_ANDROID_SELECT_FILE_DIALOG_ANDROID_H_
|
||||
#define UI_BASE_DIALOGS_ANDROID_SELECT_FILE_DIALOG_ANDROID_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "base/android/scoped_java_ref.h"
|
||||
#include "base/file_path.h"
|
||||
#include "ui/base/dialogs/select_file_dialog.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class SelectFileDialogImpl : public ui::SelectFileDialog {
|
||||
public:
|
||||
static SelectFileDialogImpl* Create(
|
||||
Listener* listener,
|
||||
ui::SelectFilePolicy* policy);
|
||||
|
||||
void OnFileSelected(JNIEnv* env, jobject java_object, jstring filepath);
|
||||
void OnFileNotSelected(JNIEnv* env, jobject java_object);
|
||||
|
||||
// From SelectFileDialog
|
||||
virtual bool IsRunning(gfx::NativeWindow) const OVERRIDE;
|
||||
virtual void ListenerDestroyed() OVERRIDE;
|
||||
|
||||
// Called when it is time to display the file picker.
|
||||
// params is expected to be a Vector<string16> with accept_types first and
|
||||
// the capture value as the last element of the vector.
|
||||
virtual void SelectFileImpl(
|
||||
ui::SelectFileDialog::Type type,
|
||||
const string16& title,
|
||||
const FilePath& default_path,
|
||||
const ui::SelectFileDialog::FileTypeInfo* file_types,
|
||||
int file_type_index,
|
||||
const std::string& default_extension,
|
||||
gfx::NativeWindow owning_window,
|
||||
void* params) OVERRIDE;
|
||||
|
||||
static bool RegisterSelectFileDialog(JNIEnv* env);
|
||||
|
||||
protected:
|
||||
virtual ~SelectFileDialogImpl();
|
||||
|
||||
private:
|
||||
SelectFileDialogImpl(Listener* listener, ui::SelectFilePolicy* policy);
|
||||
|
||||
virtual bool HasMultipleFileTypeChoicesImpl() OVERRIDE;
|
||||
|
||||
base::android::ScopedJavaGlobalRef<jobject> java_object_;
|
||||
|
||||
// Stores the state whether select_file_dialog is running.
|
||||
bool is_running_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
|
||||
};
|
||||
|
||||
SelectFileDialog* CreateAndroidSelectFileDialog(
|
||||
SelectFileDialog::Listener* listener,
|
||||
SelectFilePolicy* policy);
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif // UI_BASE_DIALOGS_ANDROID_SELECT_FILE_DIALOG_ANDROID_H_
|
46
ui/gfx/android/window_android.cc
Normal file
46
ui/gfx/android/window_android.cc
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "window_android.h"
|
||||
|
||||
#include "base/android/jni_android.h"
|
||||
#include "base/android/jni_helper.h"
|
||||
#include "base/android/scoped_java_ref.h"
|
||||
#include "jni/NativeWindow_jni.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
using base::android::AttachCurrentThread;
|
||||
using base::android::ScopedJavaLocalRef;
|
||||
|
||||
WindowAndroid::WindowAndroid(JNIEnv* env, jobject obj)
|
||||
: weak_java_window_(env, obj) {
|
||||
}
|
||||
|
||||
void WindowAndroid::Destroy(JNIEnv* env, jobject obj) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
ScopedJavaLocalRef<jobject> WindowAndroid::GetJavaObject() {
|
||||
JNIEnv* env = AttachCurrentThread();
|
||||
return weak_java_window_.get(env);
|
||||
}
|
||||
|
||||
bool WindowAndroid::RegisterWindowAndroid(JNIEnv* env) {
|
||||
return RegisterNativesImpl(env);
|
||||
}
|
||||
|
||||
WindowAndroid::~WindowAndroid() {
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Native JNI methods
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
jint Init(JNIEnv* env, jobject obj) {
|
||||
WindowAndroid* window = new WindowAndroid(env, obj);
|
||||
return reinterpret_cast<jint>(window);
|
||||
}
|
||||
|
||||
} // namespace ui
|
35
ui/gfx/android/window_android.h
Normal file
35
ui/gfx/android/window_android.h
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef UI_GFX_ANDROID_WINDOW_ANDROID_H_
|
||||
#define UI_GFX_ANDROID_WINDOW_ANDROID_H_
|
||||
|
||||
#include <jni.h>
|
||||
#include "base/android/jni_helper.h"
|
||||
#include "base/android/scoped_java_ref.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
// Android implementation of the activity window.
|
||||
class WindowAndroid {
|
||||
public:
|
||||
WindowAndroid(JNIEnv* env, jobject obj);
|
||||
|
||||
void Destroy(JNIEnv* env, jobject obj);
|
||||
|
||||
base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
|
||||
|
||||
static bool RegisterWindowAndroid(JNIEnv* env);
|
||||
|
||||
private:
|
||||
~WindowAndroid();
|
||||
|
||||
JavaObjectWeakGlobalRef weak_java_window_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WindowAndroid);
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif // UI_GFX_ANDROID_WINDOW_ANDROID_H_
|
@ -110,6 +110,9 @@ struct ANativeWindow;
|
||||
namespace content {
|
||||
class ContentViewCore;
|
||||
}
|
||||
namespace ui {
|
||||
class WindowAndroid;
|
||||
}
|
||||
#endif
|
||||
class SkBitmap;
|
||||
|
||||
@ -146,7 +149,7 @@ typedef GdkEvent* NativeEvent;
|
||||
#elif defined(OS_ANDROID)
|
||||
typedef void* NativeCursor;
|
||||
typedef content::ContentViewCore* NativeView;
|
||||
typedef content::ContentViewCore* NativeWindow;
|
||||
typedef ui::WindowAndroid* NativeWindow;
|
||||
typedef void* NativeRegion;
|
||||
typedef jobject NativeEvent;
|
||||
#endif
|
||||
|
47
ui/ui.gyp
47
ui/ui.gyp
@ -98,6 +98,8 @@
|
||||
],
|
||||
'all_sources': [
|
||||
'<@(_common_sources)',
|
||||
'android/ui_jni_registrar.cc',
|
||||
'android/ui_jni_registrar.h',
|
||||
'base/accelerators/accelerator.cc',
|
||||
'base/accelerators/accelerator.h',
|
||||
'base/accelerators/accelerator_cocoa.h',
|
||||
@ -178,6 +180,8 @@
|
||||
'base/dialogs/gtk/select_file_dialog_impl_kde.cc',
|
||||
'base/dialogs/select_file_dialog.cc',
|
||||
'base/dialogs/select_file_dialog.h',
|
||||
'base/dialogs/select_file_dialog_android.cc',
|
||||
'base/dialogs/select_file_dialog_android.h',
|
||||
'base/dialogs/select_file_dialog_factory.cc',
|
||||
'base/dialogs/select_file_dialog_factory.h',
|
||||
'base/dialogs/select_file_dialog_mac.h',
|
||||
@ -398,6 +402,8 @@
|
||||
'gfx/android/gfx_jni_registrar.h',
|
||||
'gfx/android/java_bitmap.cc',
|
||||
'gfx/android/java_bitmap.h',
|
||||
'gfx/android/window_android.cc',
|
||||
'gfx/android/window_android.h',
|
||||
'gfx/blit.cc',
|
||||
'gfx/blit.h',
|
||||
'gfx/canvas.cc',
|
||||
@ -785,6 +791,16 @@
|
||||
'gfx/platform_font_pango.cc',
|
||||
'gfx/platform_font_pango.h',
|
||||
],
|
||||
'dependencies': [
|
||||
'ui_java',
|
||||
'ui_jni_headers',
|
||||
],
|
||||
'include_dirs': [
|
||||
'<(SHARED_INTERMEDIATE_DIR)/ui',
|
||||
],
|
||||
'export_dependent_settings': [
|
||||
'ui_java',
|
||||
],
|
||||
}],
|
||||
['OS=="android" or OS=="ios"', {
|
||||
'sources!': [
|
||||
@ -811,5 +827,36 @@
|
||||
'ui_unittests.gypi',
|
||||
]},
|
||||
],
|
||||
['OS=="android"' , {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'ui_jni_headers',
|
||||
'type': 'none',
|
||||
'sources': [
|
||||
'android/java/src/org/chromium/ui/gfx/NativeWindow.java',
|
||||
'android/java/src/org/chromium/ui/SelectFileDialog.java',
|
||||
],
|
||||
'variables': {
|
||||
'jni_gen_dir': 'ui',
|
||||
},
|
||||
'includes': [ '../build/jni_generator.gypi' ],
|
||||
},
|
||||
{
|
||||
'target_name': 'ui_java',
|
||||
'type': 'none',
|
||||
'variables': {
|
||||
'package_name': 'ui',
|
||||
'java_in_dir': '../ui/android/java',
|
||||
},
|
||||
'dependencies': [
|
||||
'../base/base.gyp:base_java',
|
||||
],
|
||||
'export_dependent_settings': [
|
||||
'../base/base.gyp:base_java',
|
||||
],
|
||||
'includes': [ '../build/java.gypi' ],
|
||||
},
|
||||
],
|
||||
}],
|
||||
],
|
||||
}
|
||||
|
Reference in New Issue
Block a user