Merge change 8620 into donut
* changes:
Fix swapped gsm/cdma function dispatch, and 7bit text fragmentation.
diff --git a/api/current.xml b/api/current.xml
index d56263f..dd13db5 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -698,7 +698,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value=""android.permission.READ_HISTORY_BOOKMARKS""
+ value=""com.android.browser.permission.READ_HISTORY_BOOKMARKS""
static="true"
final="true"
deprecated="not deprecated"
@@ -1160,7 +1160,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value=""android.permission.WRITE_HISTORY_BOOKMARKS""
+ value=""com.android.browser.permission.WRITE_HISTORY_BOOKMARKS""
static="true"
final="true"
deprecated="not deprecated"
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 182843a..e21b1d9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3753,6 +3753,14 @@
data.info = getPackageInfoNoCheck(data.appInfo);
+ /**
+ * Switch this process to density compatibility mode if needed.
+ */
+ if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
+ == 0) {
+ Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
+ }
+
if (data.debugMode != IApplicationThread.DEBUG_OFF) {
// XXX should have option to change the port.
Debug.changeDebugPort(8100);
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 26b5b7a..dd70130 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -800,7 +800,6 @@
if (!event.isSystem() &&
(keyCode != KeyEvent.KEYCODE_DPAD_UP) &&
- (keyCode != KeyEvent.KEYCODE_DPAD_DOWN) &&
(keyCode != KeyEvent.KEYCODE_DPAD_LEFT) &&
(keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) &&
(keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) {
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 0631ad5..fd559d6 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1215,18 +1215,13 @@
= "DialogCursorProtocol.POST_REFRESH.displayNotify";
/**
- * Just before closing the cursor.
- */
- public final static int PRE_CLOSE = 1;
- public final static String PRE_CLOSE_SEND_MAX_DISPLAY_POS
- = "DialogCursorProtocol.PRE_CLOSE.sendDisplayPosition";
-
- /**
* When a position has been clicked.
*/
public final static int CLICK = 2;
public final static String CLICK_SEND_POSITION
= "DialogCursorProtocol.CLICK.sendPosition";
+ public final static String CLICK_SEND_MAX_DISPLAY_POS
+ = "DialogCursorProtocol.CLICK.sendDisplayPosition";
public final static String CLICK_RECEIVE_SELECTED_POS
= "DialogCursorProtocol.CLICK.receiveSelectedPosition";
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 17e6e50..4a00e48 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -194,10 +194,6 @@
public void changeCursor(Cursor c) {
if (DBG) Log.d(LOG_TAG, "changeCursor(" + c + ")");
- if (mCursor != null) {
- callCursorPreClose(mCursor);
- }
-
try {
super.changeCursor(c);
if (c != null) {
@@ -213,22 +209,6 @@
}
}
- /**
- * Handle sending and receiving information associated with
- * {@link DialogCursorProtocol#PRE_CLOSE}.
- *
- * @param cursor The cursor to call.
- */
- private void callCursorPreClose(Cursor cursor) {
- if (!mGlobalSearchMode) return;
- final Bundle request = new Bundle();
- request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.PRE_CLOSE);
- request.putInt(DialogCursorProtocol.PRE_CLOSE_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
- final Bundle response = cursor.respond(request);
-
- mMaxDisplayed = -1;
- }
-
@Override
public void notifyDataSetChanged() {
if (DBG) Log.d(LOG_TAG, "notifyDataSetChanged");
@@ -274,7 +254,9 @@
final Bundle request = new Bundle(1);
request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.CLICK);
request.putInt(DialogCursorProtocol.CLICK_SEND_POSITION, position);
+ request.putInt(DialogCursorProtocol.CLICK_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
final Bundle response = cursor.respond(request);
+ mMaxDisplayed = -1;
mListItemToSelect = response.getInt(
DialogCursorProtocol.CLICK_RECEIVE_SELECTED_POS, SuggestionsAdapter.NONE);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index fcf946f..6936435 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -545,7 +545,6 @@
private ZoomButtonsController mZoomButtonsController;
private ImageView mZoomOverviewButton;
- private ImageView mZoomFitPageButton;
// These keep track of the center point of the zoom. They are used to
// determine the point around which we should zoom.
@@ -617,6 +616,16 @@
// Create the buttons controller
mZoomButtonsController = new ZoomButtonsController(this);
mZoomButtonsController.setOnZoomListener(mZoomListener);
+ // ZoomButtonsController positions the buttons at the bottom, but in
+ // the middle. Change their layout parameters so they appear on the
+ // right.
+ View controls = mZoomButtonsController.getZoomControls();
+ ViewGroup.LayoutParams params = controls.getLayoutParams();
+ if (params instanceof FrameLayout.LayoutParams) {
+ FrameLayout.LayoutParams frameParams = (FrameLayout.LayoutParams)
+ params;
+ frameParams.gravity = Gravity.RIGHT;
+ }
// Create the accessory buttons
LayoutInflater inflater =
@@ -636,15 +645,6 @@
}
}
});
- mZoomFitPageButton =
- (ImageView) container.findViewById(com.android.internal.R.id.zoom_fit_page);
- mZoomFitPageButton.setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- zoomWithPreview(mDefaultScale);
- updateZoomButtonsEnabled();
- }
- });
}
private void updateZoomButtonsEnabled() {
@@ -654,17 +654,14 @@
// Hide the zoom in and out buttons, as well as the fit to page
// button, if the page cannot zoom
mZoomButtonsController.getZoomControls().setVisibility(View.GONE);
- mZoomFitPageButton.setVisibility(View.GONE);
} else {
// Bring back the hidden zoom controls.
mZoomButtonsController.getZoomControls()
.setVisibility(View.VISIBLE);
- mZoomFitPageButton.setVisibility(View.VISIBLE);
// Set each one individually, as a page may be able to zoom in
// or out.
mZoomButtonsController.setZoomInEnabled(canZoomIn);
mZoomButtonsController.setZoomOutEnabled(canZoomOut);
- mZoomFitPageButton.setEnabled(mActualScale != mDefaultScale);
}
mZoomOverviewButton.setVisibility(canZoomScrollOut() ? View.VISIBLE:
View.GONE);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 00d9cf6..e16db61 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -209,7 +209,7 @@
<!-- Allows an application to read (but not write) the user's
browsing history and bookmarks. -->
- <permission android:name="android.permission.READ_HISTORY_BOOKMARKS"
+ <permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:label="@string/permlab_readHistoryBookmarks"
android:description="@string/permdesc_readHistoryBookmarks"
@@ -217,7 +217,7 @@
<!-- Allows an application to write (but not read) the user's
browsing history and bookmarks. -->
- <permission android:name="android.permission.WRITE_HISTORY_BOOKMARKS"
+ <permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:label="@string/permlab_writeHistoryBookmarks"
android:description="@string/permdesc_writeHistoryBookmarks"
diff --git a/core/res/res/drawable/rate_star_small_half.png b/core/res/res/drawable/rate_star_small_half.png
index a81449b..437a11c 100644
--- a/core/res/res/drawable/rate_star_small_half.png
+++ b/core/res/res/drawable/rate_star_small_half.png
Binary files differ
diff --git a/core/res/res/drawable/rate_star_small_off.png b/core/res/res/drawable/rate_star_small_off.png
index 618766f..6fb0a36 100644
--- a/core/res/res/drawable/rate_star_small_off.png
+++ b/core/res/res/drawable/rate_star_small_off.png
Binary files differ
diff --git a/core/res/res/drawable/rate_star_small_on.png b/core/res/res/drawable/rate_star_small_on.png
index 74e3280..5392361 100644
--- a/core/res/res/drawable/rate_star_small_on.png
+++ b/core/res/res/drawable/rate_star_small_on.png
Binary files differ
diff --git a/core/res/res/layout/zoom_browser_accessory_buttons.xml b/core/res/res/layout/zoom_browser_accessory_buttons.xml
index 4bf2bdf..69afca9 100644
--- a/core/res/res/layout/zoom_browser_accessory_buttons.xml
+++ b/core/res/res/layout/zoom_browser_accessory_buttons.xml
@@ -18,18 +18,11 @@
*/
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <ImageView android:id="@+id/zoom_fit_page"
- android:background="@android:drawable/btn_browser_zoom_fit_page"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|left"
- android:layout_marginLeft="7dip"
- />
<ImageView android:id="@+id/zoom_page_overview"
android:background="@android:drawable/btn_browser_zoom_page_overview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="bottom|right"
- android:layout_marginRight="7dip"
+ android:layout_gravity="bottom|left"
+ android:layout_marginLeft="7dip"
/>
</merge>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index bb19229..eef1096 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -46,10 +46,29 @@
private boolean mRecycled;
// Package-scoped for fast access.
- /*package*/ int mDensity = DENSITY_NONE;
+ /*package*/ int mDensity = sDefaultDensity = getDefaultDensity();
private static volatile Matrix sScaleMatrix;
+ private static volatile int sDefaultDensity = -1;
+
+ /**
+ * For backwards compatibility, allows the app layer to change the default
+ * density when running old apps.
+ * @hide
+ */
+ public static void setDefaultDensity(int density) {
+ sDefaultDensity = density;
+ }
+
+ /*package*/ static int getDefaultDensity() {
+ if (sDefaultDensity >= 0) {
+ return sDefaultDensity;
+ }
+ sDefaultDensity = DisplayMetrics.DENSITY_DEVICE;
+ return sDefaultDensity;
+ }
+
/**
* @noinspection UnusedDeclaration
*/
@@ -72,9 +91,16 @@
/**
* <p>Returns the density for this bitmap.</p>
*
- * <p>The default density scale is {@link #DENSITY_NONE}.</p>
+ * <p>The default density is the same density as the current display,
+ * unless the current application does not support different screen
+ * densities in which case it is
+ * {@link android.util.DisplayMetrics#DENSITY_DEFAULT}. Note that
+ * compatibility mode is determined by the application that was initially
+ * loaded into a process -- applications that share the same process should
+ * all have the same compatibility, or ensure they explicitly set the
+ * density of their bitmaps appropriately.</p>
*
- * @return A scaling factor of the default density (160) or {@link #DENSITY_NONE}
+ * @return A scaling factor of the default density or {@link #DENSITY_NONE}
* if the scaling factor is unknown.
*
* @see #setDensity(int)
@@ -272,7 +298,8 @@
* Tries to make a new bitmap based on the dimensions of this bitmap,
* setting the new bitmap's config to the one specified, and then copying
* this bitmap's pixels into the new bitmap. If the conversion is not
- * supported, or the allocator fails, then this returns NULL.
+ * supported, or the allocator fails, then this returns NULL. The returned
+ * bitmap initially has the same density as the original.
*
* @param config The desired config for the resulting bitmap
* @param isMutable True if the resulting bitmap should be mutable (i.e.
@@ -281,7 +308,11 @@
*/
public Bitmap copy(Config config, boolean isMutable) {
checkRecycled("Can't copy a recycled bitmap");
- return nativeCopy(mNativeBitmap, config.nativeInt, isMutable);
+ Bitmap b = nativeCopy(mNativeBitmap, config.nativeInt, isMutable);
+ if (b != null) {
+ b.mDensity = mDensity;
+ }
+ return b;
}
public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
@@ -316,7 +347,8 @@
/**
* Returns an immutable bitmap from the source bitmap. The new bitmap may
- * be the same object as source, or a copy may have been made.
+ * be the same object as source, or a copy may have been made. It is
+ * initialized with the same density as the original bitmap.
*/
public static Bitmap createBitmap(Bitmap src) {
return createBitmap(src, 0, 0, src.getWidth(), src.getHeight());
@@ -325,7 +357,8 @@
/**
* Returns an immutable bitmap from the specified subset of the source
* bitmap. The new bitmap may be the same object as source, or a copy may
- * have been made.
+ * have been made. It is
+ * initialized with the same density as the original bitmap.
*
* @param source The bitmap we are subsetting
* @param x The x coordinate of the first pixel in source
@@ -339,7 +372,8 @@
/**
* Returns an immutable bitmap from subset of the source bitmap,
- * transformed by the optional matrix.
+ * transformed by the optional matrix. It is
+ * initialized with the same density as the original bitmap.
*
* @param source The bitmap we are subsetting
* @param x The x coordinate of the first pixel in source
@@ -406,18 +440,20 @@
paint.setAntiAlias(true);
}
}
- canvas.setBitmap(bitmap);
- canvas.drawBitmap(source, srcR, dstR, paint);
-
+
// The new bitmap was created from a known bitmap source so assume that
// they use the same density
bitmap.mDensity = source.mDensity;
+
+ canvas.setBitmap(bitmap);
+ canvas.drawBitmap(source, srcR, dstR, paint);
return bitmap;
}
/**
- * Returns a mutable bitmap with the specified width and height.
+ * Returns a mutable bitmap with the specified width and height. Its
+ * initial density is as per {@link #getDensity}.
*
* @param width The width of the bitmap
* @param height The height of the bitmap
@@ -432,7 +468,8 @@
/**
* Returns a immutable bitmap with the specified width and height, with each
- * pixel value set to the corresponding value in the colors array.
+ * pixel value set to the corresponding value in the colors array. Its
+ * initial density is as per {@link #getDensity}.
*
* @param colors Array of {@link Color} used to initialize the pixels.
* @param offset Number of values to skip before the first color in the
@@ -466,7 +503,8 @@
/**
* Returns a immutable bitmap with the specified width and height, with each
- * pixel value set to the corresponding value in the colors array.
+ * pixel value set to the corresponding value in the colors array. Its
+ * initial density is as per {@link #getDensity}.
*
* @param colors Array of {@link Color} used to initialize the pixels.
* This array must be at least as large as width * height.
@@ -882,6 +920,9 @@
* -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then
* drawing the original would result in the blur visually aligning with
* the original.
+ *
+ * <p>The initial density of the returned bitmap is the same as the original's.
+ *
* @param paint Optional paint used to modify the alpha values in the
* resulting bitmap. Pass null for default behavior.
* @param offsetXY Optional array that returns the X (index 0) and Y
@@ -899,6 +940,7 @@
if (bm == null) {
throw new RuntimeException("Failed to extractAlpha on Bitmap");
}
+ bm.mDensity = mDensity;
return bm;
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 8ecbfbd..bc2e42e 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -49,7 +49,7 @@
private DrawFilter mDrawFilter;
// Package-scoped for quick access.
- /*package*/ int mDensity = DisplayMetrics.DENSITY_DEFAULT;
+ /*package*/ int mDensity = Bitmap.DENSITY_NONE;
// Used by native code
@SuppressWarnings({"UnusedDeclaration"})
@@ -57,7 +57,9 @@
/**
* Construct an empty raster canvas. Use setBitmap() to specify a bitmap to
- * draw into.
+ * draw into. The initial target density is {@link Bitmap#DENSITY_NONE};
+ * this will typically be replaced when a target bitmap is set for the
+ * canvas.
*/
public Canvas() {
// 0 means no native bitmap
@@ -67,6 +69,9 @@
/**
* Construct a canvas with the specified bitmap to draw into. The bitmap
* must be mutable.
+ *
+ * <p>The initial target density of the canvas is the same as the given
+ * bitmap's density.
*
* @param bitmap Specifies a mutable bitmap for the canvas to draw into.
*/
@@ -78,9 +83,7 @@
throwIfRecycled(bitmap);
mNativeCanvas = initRaster(bitmap.ni());
mBitmap = bitmap;
- final int density = bitmap.mDensity;
- mDensity = density == Bitmap.DENSITY_NONE
- ? DisplayMetrics.DENSITY_DEFAULT : density;
+ mDensity = bitmap.mDensity;
}
/*package*/ Canvas(int nativeCanvas) {
@@ -88,6 +91,7 @@
throw new IllegalStateException();
}
mNativeCanvas = nativeCanvas;
+ mDensity = Bitmap.getDefaultDensity();
}
/**
@@ -96,10 +100,14 @@
* be supported in this mode (e.g. some GL implementations may not support
* antialiasing or certain effects like ColorMatrix or certain Xfermodes).
* However, no exception will be thrown in those cases.
+ *
+ * <p>The initial target density of the canvas is the same as the initial
+ * density of bitmaps as per {@link Bitmap#getDensity() Bitmap.getDensity()}.
*/
public Canvas(GL gl) {
mNativeCanvas = initGL();
mGL = gl;
+ mDensity = Bitmap.getDefaultDensity();
}
/**
@@ -120,9 +128,13 @@
}
/**
- * Specify a bitmap for the canvas to draw into.
+ * Specify a bitmap for the canvas to draw into. As a side-effect, also
+ * updates the canvas's target density to match that of the bitmap.
*
* @param bitmap Specifies a mutable bitmap for the canvas to draw into.
+ *
+ * @see #setDensity(int)
+ * @see #getDensity()
*/
public void setBitmap(Bitmap bitmap) {
if (!bitmap.isMutable()) {
@@ -135,9 +147,7 @@
native_setBitmap(mNativeCanvas, bitmap.ni());
mBitmap = bitmap;
- final int density = bitmap.mDensity;
- mDensity = density == Bitmap.DENSITY_NONE
- ? DisplayMetrics.DENSITY_DEFAULT : density;
+ mDensity = bitmap.mDensity;
}
/**
@@ -176,12 +186,12 @@
public native int getHeight();
/**
- * <p>Returns the density for this Canvas' backing bitmap.</p>
+ * <p>Returns the target density of the canvas. The default density is
+ * derived from the density of its backing bitmap, or
+ * {@link Bitmap#DENSITY_NONE} if there is not one.</p>
*
- * <p>The default density scale is {@link Bitmap#DENSITY_NONE}.</p>
- *
- * @return A scaling factor of the default density (160dpi) or
- * {@link Bitmap#DENSITY_NONE} if the scaling factor is unknown.
+ * @return Returns the current target density of the canvas, which is used
+ * to determine the scaling factor when drawing a bitmap into it.
*
* @see #setDensity(int)
* @see Bitmap#getDensity()
@@ -191,10 +201,13 @@
}
/**
- * <p>Specifies the density for this Canvas' backing bitmap.
+ * <p>Specifies the density for this Canvas' backing bitmap. This modifies
+ * the target density of the canvas itself, as well as the density of its
+ * backing bitmap via {@link Bitmap#setDensity(int) Bitmap.setDensity(int)}.
*
- * @param density The density scaling factor to use with this bitmap or
- * {@link Bitmap#DENSITY_NONE} if the factor is unknown.
+ * @param density The new target density of the canvas, which is used
+ * to determine the scaling factor when drawing a bitmap into it. Use
+ * {@link Bitmap#DENSITY_NONE} to disable bitmap scaling.
*
* @see #getDensity()
* @see Bitmap#setDensity(int)
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index e52ba80..6832862 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -109,7 +109,9 @@
mFilename = file;
}
}
-
+ // If the speech queue is locked for more than 5 seconds, something has gone
+ // very wrong with processSpeechQueue.
+ private static final int SPEECHQUEUELOCK_TIMEOUT = 5000;
private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000;
private static final int MAX_FILENAME_LENGTH = 250;
// TODO use the TTS stream type when available
@@ -389,9 +391,8 @@
int result = TextToSpeech.TTS_ERROR;
boolean speechQueueAvailable = false;
try{
- // If the queue is locked for more than 1 second,
- // something has gone very wrong with processSpeechQueue.
- speechQueueAvailable = speechQueueLock.tryLock(1000, TimeUnit.MILLISECONDS);
+ speechQueueAvailable =
+ speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
if (speechQueueAvailable) {
Log.i("TtsService", "Stopping");
for (int i = mSpeechQueue.size() - 1; i > -1; i--){
@@ -439,9 +440,8 @@
int result = TextToSpeech.TTS_ERROR;
boolean speechQueueAvailable = false;
try{
- // If the queue is locked for more than 1 second,
- // something has gone very wrong with processSpeechQueue.
- speechQueueAvailable = speechQueueLock.tryLock(1000, TimeUnit.MILLISECONDS);
+ speechQueueAvailable =
+ speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
if (speechQueueAvailable) {
for (int i = mSpeechQueue.size() - 1; i > -1; i--){
if (mSpeechQueue.get(i).mType != SpeechItem.TEXT_TO_FILE){
@@ -752,8 +752,10 @@
private void processSpeechQueue() {
boolean speechQueueAvailable = false;
try {
- speechQueueAvailable = speechQueueLock.tryLock();
+ speechQueueAvailable =
+ speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
if (!speechQueueAvailable) {
+ Log.e("TtsService", "processSpeechQueue - Speech queue is unavailable.");
return;
}
if (mSpeechQueue.size() < 1) {
@@ -822,6 +824,9 @@
if (mSpeechQueue.size() > 0) {
mSpeechQueue.remove(0);
}
+ } catch (InterruptedException e) {
+ Log.e("TtsService", "TTS processSpeechQueue: tryLock interrupted");
+ e.printStackTrace();
} finally {
// This check is needed because finally will always run; even if the
// method returns somewhere in the try block.