Commit d4f8cd3b authored by tedchoc@chromium.org's avatar tedchoc@chromium.org

Add support for closing Android Shell instances from Java.

This also fixes an issue where the java side would be deleted when
calling launchShell, but the native counter part was not being cleaned
up.

BUG=330902
TBR=avi@chromium.org

Review URL: https://codereview.chromium.org/117403003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@244022 0039d316-1c4b-4281-b951-d872f2087c98
parent df1e4fc9
......@@ -821,6 +821,7 @@
],
'variables': {
'jni_gen_package': 'content/shell',
'jni_generator_ptr_type': 'long',
},
'includes': [ '../build/jni_generator.gypi' ],
},
......
......@@ -49,6 +49,7 @@ public class Shell extends LinearLayout {
private ClipDrawable mProgressDrawable;
private long mNativeShell;
private ContentViewRenderView mContentViewRenderView;
private WindowAndroid mWindow;
......@@ -80,12 +81,42 @@ public class Shell extends LinearLayout {
}
/**
* Initializes the Shell for use.
*
* @param nativeShell The pointer to the native Shell object.
* @param window The owning window for this shell.
*/
public void setWindow(WindowAndroid window) {
public void initialize(long nativeShell, WindowAndroid window) {
mNativeShell = nativeShell;
mWindow = window;
}
/**
* Closes the shell and cleans up the native instance, which will handle destroying all
* dependencies.
*/
public void close() {
if (mNativeShell == 0) return;
nativeCloseShell(mNativeShell);
}
@CalledByNative
private void onNativeDestroyed() {
mWindow = null;
mNativeShell = 0;
assert !mContentView.isAttachedToWindow()
: "Attempting to destroy the content view while attached to the view hierarchy.";
mContentView.destroy();
}
/**
* @return Whether the Shell has been destroyed.
* @see #onNativeDestroyed()
*/
public boolean isDestroyed() {
return mNativeShell == 0;
}
/**
* @return Whether or not the Shell is loading content.
*/
......@@ -242,4 +273,6 @@ public class Shell extends LinearLayout {
imm.hideSoftInputFromWindow(mUrlTextView.getWindowToken(), 0);
}
}
private static native void nativeCloseShell(long shellPtr);
}
......@@ -11,6 +11,7 @@ import android.widget.FrameLayout;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import org.chromium.base.ThreadUtils;
import org.chromium.content.browser.ContentView;
import org.chromium.content.browser.ContentViewRenderView;
import org.chromium.ui.base.WindowAndroid;
......@@ -82,6 +83,7 @@ public class ShellManager extends FrameLayout {
* @param url The URL the shell should load upon creation.
*/
public void launchShell(String url) {
ThreadUtils.assertOnUiThread();
nativeLaunchShell(url);
}
......@@ -96,14 +98,14 @@ public class ShellManager extends FrameLayout {
@SuppressWarnings("unused")
@CalledByNative
private Object createShell() {
private Object createShell(long nativeShellPtr) {
assert mContentViewRenderView != null;
LayoutInflater inflater =
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Shell shellView = (Shell) inflater.inflate(R.layout.shell_view, null);
shellView.setWindow(mWindow);
shellView.initialize(nativeShellPtr, mWindow);
if (mActiveShell != null) closeShell(mActiveShell);
if (mActiveShell != null) mActiveShell.close();
shellView.setContentViewRenderView(mContentViewRenderView);
addView(shellView, new FrameLayout.LayoutParams(
......@@ -120,12 +122,11 @@ public class ShellManager extends FrameLayout {
@SuppressWarnings("unused")
@CalledByNative
private void closeShell(Shell shellView) {
private void removeShell(Shell shellView) {
if (shellView == mActiveShell) mActiveShell = null;
ContentView contentView = shellView.getContentView();
if (contentView != null) contentView.onHide();
shellView.setContentViewRenderView(null);
shellView.setWindow(null);
removeView(shellView);
}
......
// Copyright 2014 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.content_shell_apk;
import android.test.suitebuilder.annotation.SmallTest;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.UrlUtils;
import org.chromium.content_shell.Shell;
/**
* Test suite to verify the behavior of the shell management logic.
*/
public class ContentShellShellManagementTest extends ContentShellTestBase {
private static final String TEST_PAGE_1 = UrlUtils.encodeHtmlDataUri(
"<html><body style='background: red;'></body></html>");
private static final String TEST_PAGE_2 = UrlUtils.encodeHtmlDataUri(
"<html><body style='background: green;'></body></html>");
@SmallTest
@Feature({"Main"})
public void testMultipleShellsLaunched() throws InterruptedException {
final ContentShellActivity activity = launchContentShellWithUrl(TEST_PAGE_1);
assertEquals(TEST_PAGE_1, activity.getActiveShell().getContentView().getUrl());
Shell previousActiveShell = activity.getActiveShell();
assertFalse(previousActiveShell.isDestroyed());
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
activity.getShellManager().launchShell(TEST_PAGE_2);
}
});
waitForActiveShellToBeDoneLoading();
assertEquals(TEST_PAGE_2, activity.getActiveShell().getContentView().getUrl());
assertNotSame(previousActiveShell, activity.getActiveShell());
assertTrue(previousActiveShell.isDestroyed());
assertFalse(previousActiveShell.getContentView().isAlive());
}
}
......@@ -34,13 +34,16 @@ namespace content {
jobject CreateShellView(Shell* shell) {
JNIEnv* env = base::android::AttachCurrentThread();
jobject j_shell_manager = g_global_state.Get().j_shell_manager.obj();
return Java_ShellManager_createShell(env, j_shell_manager).Release();
return Java_ShellManager_createShell(
env,
j_shell_manager,
reinterpret_cast<intptr_t>(shell)).Release();
}
void CloseShellView(jobject shell_view) {
void RemoveShellView(jobject shell_view) {
JNIEnv* env = base::android::AttachCurrentThread();
jobject j_shell_manager = g_global_state.Get().j_shell_manager.obj();
Java_ShellManager_closeShell(env, j_shell_manager, shell_view);
Java_ShellManager_removeShell(env, j_shell_manager, shell_view);
}
// Register native methods
......
......@@ -24,8 +24,8 @@ namespace content {
// object.
jobject CreateShellView(Shell* shell);
// Closes a previously created shell view.
void CloseShellView(jobject shell_view);
// Removes a previously created shell view.
void RemoveShellView(jobject shell_view);
// Registers the ShellManager native methods.
bool RegisterShellManager(JNIEnv* env);
......
......@@ -30,6 +30,10 @@ void Shell::PlatformExit() {
}
void Shell::PlatformCleanUp() {
JNIEnv* env = AttachCurrentThread();
if (java_object_.is_null())
return;
Java_Shell_onNativeDestroyed(env, java_object_.obj());
}
void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
......@@ -83,8 +87,7 @@ bool Shell::PlatformIsFullscreenForTabOrPending(
}
void Shell::Close() {
CloseShellView(java_object_.obj());
java_object_.Reset();
RemoveShellView(java_object_.obj());
delete this;
}
......@@ -93,4 +96,10 @@ bool Shell::Register(JNIEnv* env) {
return RegisterNativesImpl(env);
}
// static
void CloseShell(JNIEnv* env, jclass clazz, jlong shellPtr) {
Shell* shell = reinterpret_cast<Shell*>(shellPtr);
shell->Close();
}
} // namespace content
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment