diff options
11 files changed, 247 insertions, 65 deletions
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 8f4626fe4bbe..07bb8f93e85c 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -266,6 +266,8 @@ public class Surface implements Parcelable { IBinder displayToken, int orientation, Rect layerStackRect, Rect displayRect); private static native boolean nativeGetDisplayInfo( IBinder displayToken, PhysicalDisplayInfo outInfo); + private static native void nativeBlankDisplay(IBinder displayToken); + private static native void nativeUnblankDisplay(IBinder displayToken); private native void nativeCopyFrom(Surface other); private native void nativeTransferFrom(Surface other); @@ -638,6 +640,22 @@ public class Surface implements Parcelable { return nativeGetDisplayInfo(displayToken, outInfo); } + /** @hide */ + public static void blankDisplay(IBinder displayToken) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + nativeBlankDisplay(displayToken); + } + + /** @hide */ + public static void unblankDisplay(IBinder displayToken) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + nativeUnblankDisplay(displayToken); + } + /** * Copy another surface to this one. This surface now holds a reference * to the same data as the original surface, and is -not- the owner. diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index fc04cd19c4bf..4982f31ba072 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -48,6 +48,7 @@ #include <android_runtime/android_view_SurfaceSession.h> #include <android_runtime/android_graphics_SurfaceTexture.h> #include <utils/misc.h> +#include <utils/Log.h> #include <ScopedUtfChars.h> @@ -710,6 +711,22 @@ static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz, return JNI_TRUE; } +static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) { + sp<IBinder> token(ibinderForJavaObject(env, tokenObj)); + if (token == NULL) return; + + ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off"); + SurfaceComposerClient::blankDisplay(token); +} + +static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) { + sp<IBinder> token(ibinderForJavaObject(env, tokenObj)); + if (token == NULL) return; + + ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on"); + SurfaceComposerClient::unblankDisplay(token); +} + // ---------------------------------------------------------------------------- static void nativeCopyFrom(JNIEnv* env, jobject surfaceObj, jobject otherObj) { @@ -832,6 +849,10 @@ static JNINativeMethod gSurfaceMethods[] = { (void*)nativeSetDisplayProjection }, {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/Surface$PhysicalDisplayInfo;)Z", (void*)nativeGetDisplayInfo }, + {"nativeBlankDisplay", "(Landroid/os/IBinder;)V", + (void*)nativeBlankDisplay }, + {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V", + (void*)nativeUnblankDisplay }, {"nativeCopyFrom", "(Landroid/view/Surface;)V", (void*)nativeCopyFrom }, {"nativeTransferFrom", "(Landroid/view/Surface;)V", diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index a4516abd8a67..16ad74fa4b4a 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -693,7 +693,8 @@ public class MediaRouter { final WifiDisplayStatus oldStatus = sStatic.mLastKnownWifiDisplayStatus; // TODO Naive implementation. Make this smarter later. - boolean needScan = false; + boolean wantScan = false; + boolean blockScan = false; WifiDisplay[] oldDisplays = oldStatus != null ? oldStatus.getRememberedDisplays() : new WifiDisplay[0]; WifiDisplay[] newDisplays = newStatus.getRememberedDisplays(); @@ -706,7 +707,7 @@ public class MediaRouter { if (oldRemembered == null) { addRouteStatic(makeWifiDisplayRoute(d, findMatchingDisplay(d, availableDisplays) != null)); - needScan = true; + wantScan = true; } else { final boolean available = findMatchingDisplay(d, availableDisplays) != null; final RouteInfo route = findWifiDisplayRoute(d); @@ -716,6 +717,10 @@ public class MediaRouter { final RouteInfo activeRoute = findWifiDisplayRoute(d); if (activeRoute != null) { selectRouteStatic(activeRoute.getSupportedTypes(), activeRoute); + + // Don't scan if we're already connected to a wifi display, + // the scanning process can cause a hiccup with some configurations. + blockScan = true; } } } @@ -727,7 +732,7 @@ public class MediaRouter { } } - if (needScan) { + if (wantScan && !blockScan) { sStatic.mDisplayService.scanWifiDisplays(); } diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/java/com/android/server/display/DisplayDevice.java index f5aa3d4780df..a3ab3c1f246f 100644 --- a/services/java/com/android/server/display/DisplayDevice.java +++ b/services/java/com/android/server/display/DisplayDevice.java @@ -105,6 +105,18 @@ abstract class DisplayDevice { } /** + * Blanks the display, if supported. + */ + public void blankLocked() { + } + + /** + * Unblanks the display, if supported. + */ + public void unblankLocked() { + } + + /** * Sets the display layer stack while in a transaction. */ public final void setLayerStackInTransactionLocked(int layerStack) { diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java index b8c6cd5a5035..0a4252813188 100644 --- a/services/java/com/android/server/display/DisplayManagerService.java +++ b/services/java/com/android/server/display/DisplayManagerService.java @@ -103,6 +103,10 @@ public final class DisplayManagerService extends IDisplayManager.Stub { private static final int MSG_REQUEST_TRAVERSAL = 4; private static final int MSG_UPDATE_VIEWPORT = 5; + private static final int DISPLAY_BLANK_STATE_UNKNOWN = 0; + private static final int DISPLAY_BLANK_STATE_BLANKED = 1; + private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2; + private final Context mContext; private final boolean mHeadless; private final DisplayManagerHandler mHandler; @@ -141,6 +145,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub { new SparseArray<LogicalDisplay>(); private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1; + // Set to true if all displays have been blanked by the power manager. + private int mAllDisplayBlankStateFromPowerManager; + // Set to true when there are pending display changes that have yet to be applied // to the surface flinger state. private boolean mPendingTraversal; @@ -286,6 +293,40 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } /** + * Called by the power manager to blank all displays. + */ + public void blankAllDisplaysFromPowerManager() { + synchronized (mSyncRoot) { + if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) { + mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED; + + final int count = mDisplayDevices.size(); + for (int i = 0; i < count; i++) { + DisplayDevice device = mDisplayDevices.get(i); + device.blankLocked(); + } + } + } + } + + /** + * Called by the power manager to unblank all displays. + */ + public void unblankAllDisplaysFromPowerManager() { + synchronized (mSyncRoot) { + if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) { + mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED; + + final int count = mDisplayDevices.size(); + for (int i = 0; i < count; i++) { + DisplayDevice device = mDisplayDevices.get(i); + device.unblankLocked(); + } + } + } + } + + /** * Returns information about the specified logical display. * * @param displayId The logical display id. @@ -528,6 +569,17 @@ public final class DisplayManagerService extends IDisplayManager.Stub { mDisplayDevices.add(device); addLogicalDisplayLocked(device); scheduleTraversalLocked(false); + + // Blank or unblank the display immediately to match the state requested + // by the power manager (if known). + switch (mAllDisplayBlankStateFromPowerManager) { + case DISPLAY_BLANK_STATE_BLANKED: + device.blankLocked(); + break; + case DISPLAY_BLANK_STATE_UNBLANKED: + device.unblankLocked(); + break; + } } } @@ -788,9 +840,18 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } pw.println("DISPLAY MANAGER (dumpsys display)"); - pw.println(" mHeadless=" + mHeadless); synchronized (mSyncRoot) { + pw.println(" mHeadless=" + mHeadless); + pw.println(" mOnlyCode=" + mOnlyCore); + pw.println(" mSafeMode=" + mSafeMode); + pw.println(" mPendingTraversal=" + mPendingTraversal); + pw.println(" mAllDisplayBlankStateFromPowerManager=" + + mAllDisplayBlankStateFromPowerManager); + pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId); + pw.println(" mDefaultViewport=" + mDefaultViewport); + pw.println(" mExternalTouchViewport=" + mExternalTouchViewport); + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); ipw.increaseIndent(); @@ -817,10 +878,6 @@ public final class DisplayManagerService extends IDisplayManager.Stub { pw.println(" Display " + displayId + ":"); display.dumpLocked(ipw); } - - pw.println(); - pw.println("Default viewport: " + mDefaultViewport); - pw.println("External touch viewport: " + mExternalTouchViewport); } } diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java index 679a67e4dcb3..d7800068130b 100644 --- a/services/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/java/com/android/server/display/LocalDisplayAdapter.java @@ -92,6 +92,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { private DisplayDeviceInfo mInfo; private boolean mHavePendingChanges; + private boolean mBlanked; public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId, PhysicalDisplayInfo phys) { @@ -150,10 +151,23 @@ final class LocalDisplayAdapter extends DisplayAdapter { } @Override + public void blankLocked() { + mBlanked = true; + Surface.blankDisplay(getDisplayTokenLocked()); + } + + @Override + public void unblankLocked() { + mBlanked = false; + Surface.unblankDisplay(getDisplayTokenLocked()); + } + + @Override public void dumpLocked(PrintWriter pw) { super.dumpLocked(pw); pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId); pw.println("mPhys=" + mPhys); + pw.println("mBlanked=" + mBlanked); } } diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/services/java/com/android/server/power/DisplayBlanker.java new file mode 100644 index 000000000000..6072053f96f2 --- /dev/null +++ b/services/java/com/android/server/power/DisplayBlanker.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.power; + +/** + * Blanks or unblanks all displays. + */ +interface DisplayBlanker { + public void blankAllDisplays(); + public void unblankAllDisplays(); +} diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java index 82c361760ba2..6a573727c519 100644 --- a/services/java/com/android/server/power/DisplayPowerController.java +++ b/services/java/com/android/server/power/DisplayPowerController.java @@ -159,6 +159,9 @@ final class DisplayPowerController { // A suspend blocker. private final SuspendBlocker mSuspendBlocker; + // The display blanker. + private final DisplayBlanker mDisplayBlanker; + // Our handler. private final DisplayControllerHandler mHandler; @@ -343,10 +346,12 @@ final class DisplayPowerController { */ public DisplayPowerController(Looper looper, Context context, Notifier notifier, LightsService lights, TwilightService twilight, SuspendBlocker suspendBlocker, + DisplayBlanker displayBlanker, Callbacks callbacks, Handler callbackHandler) { mHandler = new DisplayControllerHandler(looper); mNotifier = notifier; mSuspendBlocker = suspendBlocker; + mDisplayBlanker = displayBlanker; mCallbacks = callbacks; mCallbackHandler = callbackHandler; @@ -520,7 +525,8 @@ final class DisplayPowerController { new ElectronBeam(display), new PhotonicModulator(executor, mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT), - mSuspendBlocker)); + mSuspendBlocker), + mDisplayBlanker); mElectronBeamOnAnimator = ObjectAnimator.ofFloat( mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f); diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java index f6ce7a764592..fdfcacca0dba 100644 --- a/services/java/com/android/server/power/DisplayPowerState.java +++ b/services/java/com/android/server/power/DisplayPowerState.java @@ -51,7 +51,8 @@ final class DisplayPowerState { private final Choreographer mChoreographer; private final ElectronBeam mElectronBeam; - private final PhotonicModulator mScreenBrightnessModulator; + private final PhotonicModulator mPhotonicModulator; + private final DisplayBlanker mDisplayBlanker; private int mDirty; private boolean mScreenOn; @@ -61,10 +62,11 @@ final class DisplayPowerState { private Runnable mCleanListener; public DisplayPowerState(ElectronBeam electronBean, - PhotonicModulator screenBrightnessModulator) { + PhotonicModulator photonicModulator, DisplayBlanker displayBlanker) { mChoreographer = Choreographer.getInstance(); mElectronBeam = electronBean; - mScreenBrightnessModulator = screenBrightnessModulator; + mPhotonicModulator = photonicModulator; + mDisplayBlanker = displayBlanker; // At boot time, we know that the screen is on and the electron beam // animation is not playing. We don't know the screen's brightness though, @@ -238,8 +240,8 @@ final class DisplayPowerState { private void apply() { if (mDirty != 0) { if ((mDirty & DIRTY_SCREEN_ON) != 0 && !mScreenOn) { - mScreenBrightnessModulator.setBrightness(0, true /*sync*/); - PowerManagerService.nativeSetScreenState(false); + mPhotonicModulator.setBrightness(0, true /*sync*/); + mDisplayBlanker.blankAllDisplays(); } if ((mDirty & DIRTY_ELECTRON_BEAM) != 0) { @@ -247,12 +249,12 @@ final class DisplayPowerState { } if ((mDirty & DIRTY_SCREEN_ON) != 0 && mScreenOn) { - PowerManagerService.nativeSetScreenState(true); + mDisplayBlanker.unblankAllDisplays(); } if ((mDirty & (DIRTY_BRIGHTNESS | DIRTY_SCREEN_ON | DIRTY_ELECTRON_BEAM)) != 0 && mScreenOn) { - mScreenBrightnessModulator.setBrightness( + mPhotonicModulator.setBrightness( (int)(mScreenBrightness * mElectronBeamLevel), false /*sync*/); } diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java index abbae5bb0ad9..85bf17a1daae 100644 --- a/services/java/com/android/server/power/PowerManagerService.java +++ b/services/java/com/android/server/power/PowerManagerService.java @@ -155,6 +155,7 @@ public final class PowerManagerService extends IPowerManager.Stub private Context mContext; private LightsService mLightsService; private BatteryService mBatteryService; + private DisplayManagerService mDisplayManagerService; private IBatteryStats mBatteryStats; private HandlerThread mHandlerThread; private PowerManagerHandler mHandler; @@ -230,6 +231,9 @@ public final class PowerManagerService extends IPowerManager.Stub // screen is coming up. private final ScreenOnBlockerImpl mScreenOnBlocker; + // The display blanker used to turn the screen on or off. + private final DisplayBlankerImpl mDisplayBlanker; + // True if systemReady() has been called. private boolean mSystemReady; @@ -319,14 +323,15 @@ public final class PowerManagerService extends IPowerManager.Stub private static native void nativeSetPowerState(boolean screenOn, boolean screenBright); private static native void nativeAcquireSuspendBlocker(String name); private static native void nativeReleaseSuspendBlocker(String name); - - static native void nativeSetScreenState(boolean on); + private static native void nativeSetInteractive(boolean enable); + private static native void nativeSetAutoSuspend(boolean enable); public PowerManagerService() { synchronized (mLock) { mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService"); mWakeLockSuspendBlocker.acquire(); mScreenOnBlocker = new ScreenOnBlockerImpl(); + mDisplayBlanker = new DisplayBlankerImpl(); mHoldingWakeLockSuspendBlocker = true; mWakefulness = WAKEFULNESS_AWAKE; } @@ -342,23 +347,24 @@ public final class PowerManagerService extends IPowerManager.Stub public void init(Context context, LightsService ls, ActivityManagerService am, BatteryService bs, IBatteryStats bss, DisplayManagerService dm) { - // Forcibly turn the screen on at boot so that it is in a known power state. - // We do this in init() rather than in the constructor because setting the - // screen state requires a call into surface flinger which then needs to call back - // into the activity manager to check permissions. Unfortunately the - // activity manager is not running when the constructor is called, so we - // have to defer setting the screen state until this point. - nativeSetScreenState(true); - mContext = context; mLightsService = ls; mBatteryService = bs; mBatteryStats = bss; + mDisplayManagerService = dm; mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); mHandler = new PowerManagerHandler(mHandlerThread.getLooper()); Watchdog.getInstance().addMonitor(this); + + // Forcibly turn the screen on at boot so that it is in a known power state. + // We do this in init() rather than in the constructor because setting the + // screen state requires a call into surface flinger which then needs to call back + // into the activity manager to check permissions. Unfortunately the + // activity manager is not running when the constructor is called, so we + // have to defer setting the screen state until this point. + mDisplayBlanker.unblankAllDisplays(); } public void setPolicy(WindowManagerPolicy policy) { @@ -388,7 +394,7 @@ public final class PowerManagerService extends IPowerManager.Stub mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(), mContext, mNotifier, mLightsService, twilight, createSuspendBlockerLocked("PowerManagerService.Display"), - mDisplayPowerControllerCallbacks, mHandler); + mDisplayBlanker, mDisplayPowerControllerCallbacks, mHandler); mSettingsObserver = new SettingsObserver(mHandler); mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION); @@ -2106,6 +2112,9 @@ public final class PowerManagerService extends IPowerManager.Stub pw.println(); pw.println("Screen On Blocker: " + mScreenOnBlocker); + pw.println(); + pw.println("Display Blanker: " + mDisplayBlanker); + dpc = mDisplayPowerController; } @@ -2397,5 +2406,36 @@ public final class PowerManagerService extends IPowerManager.Stub return "held=" + (mNestCount != 0) + ", mNestCount=" + mNestCount; } } - }; + } + + private final class DisplayBlankerImpl implements DisplayBlanker { + private boolean mBlanked; + + @Override + public void blankAllDisplays() { + synchronized (this) { + mBlanked = true; + mDisplayManagerService.blankAllDisplaysFromPowerManager(); + nativeSetInteractive(false); + nativeSetAutoSuspend(true); + } + } + + @Override + public void unblankAllDisplays() { + synchronized (this) { + nativeSetAutoSuspend(false); + nativeSetInteractive(true); + mDisplayManagerService.unblankAllDisplaysFromPowerManager(); + mBlanked = false; + } + } + + @Override + public String toString() { + synchronized (this) { + return "blanked=" + mBlanked; + } + } + } } diff --git a/services/jni/com_android_server_power_PowerManagerService.cpp b/services/jni/com_android_server_power_PowerManagerService.cpp index dcc2b58470d5..75f77b9535a5 100644 --- a/services/jni/com_android_server_power_PowerManagerService.cpp +++ b/services/jni/com_android_server_power_PowerManagerService.cpp @@ -26,7 +26,6 @@ #include <limits.h> #include <android_runtime/AndroidRuntime.h> -#include <gui/ISurfaceComposer.h> #include <utils/Timers.h> #include <utils/misc.h> #include <utils/String8.h> @@ -36,8 +35,6 @@ #include <cutils/android_reboot.h> #include <suspend/autosuspend.h> -#include <private/gui/ComposerService.h> - #include "com_android_server_power_PowerManagerService.h" namespace android { @@ -170,40 +167,23 @@ static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameS release_wake_lock(name.c_str()); } -static void nativeSetScreenState(JNIEnv *env, jclass clazz, jboolean on) { - sp<ISurfaceComposer> s(ComposerService::getComposerService()); - if (on) { - { - ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_disable() while turning screen on"); - autosuspend_disable(); - } - - if (gPowerModule) { - ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(true) while turning screen on"); - gPowerModule->setInteractive(gPowerModule, true); - } - - const sp<IBinder>& display = s->getBuiltInDisplay(0); // TODO: support multiple displays - { - ALOGD_IF_SLOW(100, "Excessive delay in unblank() while turning screen on"); - s->unblank(display); - } +static void nativeSetInteractive(JNIEnv *env, jclass clazz, jboolean enable) { + if (enable) { + ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(true) while turning screen on"); + gPowerModule->setInteractive(gPowerModule, true); } else { - const sp<IBinder>& display = s->getBuiltInDisplay(0); // TODO: support multiple displays - { - ALOGD_IF_SLOW(100, "Excessive delay in blank() while turning screen off"); - s->blank(display); - } - - if (gPowerModule) { - ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(false) while turning screen off"); - gPowerModule->setInteractive(gPowerModule, false); - } + ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(false) while turning screen off"); + gPowerModule->setInteractive(gPowerModule, false); + } +} - { - ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_enable() while turning screen off"); - autosuspend_enable(); - } +static void nativeSetAutoSuspend(JNIEnv *env, jclass clazz, jboolean enable) { + if (enable) { + ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_enable() while turning screen off"); + autosuspend_enable(); + } else { + ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_disable() while turning screen on"); + autosuspend_disable(); } } @@ -235,8 +215,10 @@ static JNINativeMethod gPowerManagerServiceMethods[] = { (void*) nativeAcquireSuspendBlocker }, { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V", (void*) nativeReleaseSuspendBlocker }, - { "nativeSetScreenState", "(Z)V", - (void*) nativeSetScreenState }, + { "nativeSetInteractive", "(Z)V", + (void*) nativeSetInteractive }, + { "nativeSetAutoSuspend", "(Z)V", + (void*) nativeSetAutoSuspend }, { "nativeShutdown", "()V", (void*) nativeShutdown }, { "nativeReboot", "(Ljava/lang/String;)V", |