android4.2 RemoteDisplay远程显示修改为保存文件

RemoteDisplay其是具体Display的业务实现,其包含JAVA层与JNI,library三个层。

在android 4.2当中主要是WifiDisplayAdapter使用了RemoteDisplay。

也就是RemoteDisplay其是基础,WifiDisplayAdapter只是使用了其的功能!!!

pizzaframeworksasemediajavaandroidmediaRemoteDisplay.java

private native int nativeListen(String iface);
private native int nativeStartRecord(String iface);
private native int nativePauseRecord(int ptr);
private native int nativeResumeRecord(int ptr);
private native int nativeStopRecord(int ptr);
private native void nativeDispose(int ptr);

public static RemoteDisplay recordScreen(String outfile, Listener listener, Handler handler) {
     if (outfile == null) {
         throw new IllegalArgumentException("iface must not be null");
     }
     if (listener == null) {
         throw new IllegalArgumentException("listener must not be null");
     }
     if (handler == null) {
         throw new IllegalArgumentException("handler must not be null");
     }

     RemoteDisplay display = new RemoteDisplay(listener, handler);
     display.startRecording(outfile);
     return display;
}

    private void startListening(String iface) {
        mPtr = nativeListen(iface);
        if (mPtr == 0) {
            throw new IllegalStateException("Could not start listening for "
                    + "remote display connection on "" + iface + """);
        }
        mGuard.open("dispose");
        mGuard.open("stopRecording");
    }
   public void startRecording(String outfile) {
        Log.e(TAG, "### startRecording ###");
                mPtr = nativeStartRecord(outfile);
        if (mPtr == 0) {
            throw new IllegalStateException("Could not start listening for "
                    + "remote display connection on "" + outfile + """);
        }
    }

    public void pauseRecording() {
        Log.e(TAG, "### pauseRecording  ###");
        if(mPtr != 0)
            {      
                nativePauseRecord(mPtr);
            }
    }
    public void resumeRecording() {
        Log.e(TAG, "### resumeRecording  ###");
        if(mPtr != 0)
            {
                nativeResumeRecord(mPtr);
            }
    }

    public void stopRecording() {
        Log.e(TAG, "### stopRecording  ###");
     stopRecording(false);
    }

    private void stopRecording(boolean finalized) {
        if(mPtr != 0)
        {
            if (mGuardRecScr != null) {
                if (finalized) {
                    mGuardRecScr.warnIfOpen();
                } else {
                    mGuardRecScr.close();
                }
            }
              nativeStopRecord(mPtr);
        mPtr = 0;
        }
    }

// Called from native.
private void notifyRecordScreen(final byte[] buffer, final int len) {
        Log.e(TAG, "### notifyRecordScreen  ###");           
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            mListener.onRecordScreen(buffer, len);
        }
    });
}

    /**
     * Listener invoked when the remote display connection changes state.
     */
    public interface Listener {
        void onDisplayConnected(Surface surface, int width, int height, int flags);
        void onDisplayDisconnected();
        void onDisplayError(int error);
       void onRecordScreen(byte[] buffer, int len);    
}

pizzaframeworksasecorejniandroid_media_RemoteDisplay.cpp

namespace android {

static struct {
    jmethodID notifyDisplayConnected;
    jmethodID notifyDisplayDisconnected;
    jmethodID notifyDisplayError;
    jmethodID notifyRecordScreen;
} gRemoteDisplayClassInfo;

// ----------------------------------------------------------------------------

class NativeRemoteDisplayClient : public BnRemoteDisplayClient {
public:
    NativeRemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj) :
            mRemoteDisplayObjGlobal(env->NewGlobalRef(remoteDisplayObj)) {
    }

protected:
    ~NativeRemoteDisplayClient() {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        env->DeleteGlobalRef(mRemoteDisplayObjGlobal);
    }

public:
    virtual void onDisplayConnected(const sp<ISurfaceTexture>& surfaceTexture,
            uint32_t width, uint32_t height, uint32_t flags) {
        JNIEnv* env = AndroidRuntime::getJNIEnv();

        jobject surfaceObj = android_view_Surface_createFromISurfaceTexture(env, surfaceTexture);
        if (surfaceObj == NULL) {
            ALOGE("Could not create Surface from surface texture %p provided by media server.",
                    surfaceTexture.get());
            return;
        }

        env->CallVoidMethod(mRemoteDisplayObjGlobal,
                gRemoteDisplayClassInfo.notifyDisplayConnected,
                surfaceObj, width, height, flags);
        env->DeleteLocalRef(surfaceObj);
        checkAndClearExceptionFromCallback(env, "notifyDisplayConnected");
    }

    virtual void onDisplayDisconnected() {
        JNIEnv* env = AndroidRuntime::getJNIEnv();

        env->CallVoidMethod(mRemoteDisplayObjGlobal,
                gRemoteDisplayClassInfo.notifyDisplayDisconnected);
        checkAndClearExceptionFromCallback(env, "notifyDisplayDisconnected");
    }

    virtual void onDisplayError(int32_t error) {
        JNIEnv* env = AndroidRuntime::getJNIEnv();

        env->CallVoidMethod(mRemoteDisplayObjGlobal,
                gRemoteDisplayClassInfo.notifyDisplayError, error);
        checkAndClearExceptionFromCallback(env, "notifyDisplayError");
    }

  virtual void onRecordScreen(char *buffer, int len) {
    }

private:
    jobject mRemoteDisplayObjGlobal;

    static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
        if (env->ExceptionCheck()) {
            ALOGE("An exception was thrown by callback '%s'.", methodName);
            LOGE_EX(env);
            env->ExceptionClear();
        }
    }
};

class NativeRemoteDisplay {
public:
    NativeRemoteDisplay(const sp<IRemoteDisplay>& display,
            const sp<NativeRemoteDisplayClient>& client) :
            mDisplay(display), mClient(client) {
    }

    ~NativeRemoteDisplay() {
        mDisplay->dispose();
    }

private:
    sp<IRemoteDisplay> mDisplay;
    sp<NativeRemoteDisplayClient> mClient;
};

// ----------------------------------------------------------------------------

struct RemoteDisplayClient : public BnRemoteDisplayClient {
    RemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj);

    virtual void onDisplayConnected(
            const sp<ISurfaceTexture> &surfaceTexture,
            uint32_t width,
            uint32_t height,
            uint32_t flags);

    virtual void onDisplayDisconnected();
    virtual void onDisplayError(int32_t error);
    virtual void onRecordScreen(char *buffer, int len);

    void waitUntilDone();

protected:
    virtual ~RemoteDisplayClient();

private:
    JNIEnv* mEnv;

    Mutex mLock;
    Condition mCondition;

    bool mDone;

// 有了这个几个Display才能够真正的镜像显示数据

    sp<SurfaceComposerClient> mComposerClient;

    sp<ISurfaceTexture> mSurfaceTexture;

    sp<IBinder> mDisplayBinder;

    jobject mRemoteDisplayObjGlobal;
    static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
        if (env->ExceptionCheck()) {
            ALOGE("An exception was thrown by callback '%s'.", methodName);
            LOGE_EX(env);
            env->ExceptionClear();
        }
    }

    DISALLOW_EVIL_CONSTRUCTORS(RemoteDisplayClient);
};

static status_t enableAudioSubmix(bool enable) {
    status_t err = AudioSystem::setDeviceConnectionState(
            AUDIO_DEVICE_IN_REMOTE_SUBMIX,
            enable
                ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE
                : AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
            NULL /* device_address */);

    if (err != OK) {
    return err;
}

    err = AudioSystem::setDeviceConnectionState(
            AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
            enable
                ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE
                : AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
            NULL /* device_address */);

    return err;
}

RemoteDisplayClient::RemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj) :
         mEnv(env),
            mRemoteDisplayObjGlobal(env->NewGlobalRef(remoteDisplayObj)),
         mDone(false) {
    mComposerClient = new SurfaceComposerClient;
    mComposerClient->initCheck();
    //CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
}

RemoteDisplayClient::~RemoteDisplayClient() {
            JNIEnv* env = AndroidRuntime::getJNIEnv();
        env->DeleteGlobalRef(mRemoteDisplayObjGlobal);
}

void RemoteDisplayClient::onDisplayConnected(
        const sp<ISurfaceTexture> &surfaceTexture,
        uint32_t width,
        uint32_t height,
        uint32_t flags) {
    ALOGI("#### onDisplayConnected width=%u, height=%u, flags = 0x%08x",
          width, height, flags);
    if(999 == flags)
    {
        onRecordScreen((char *)width, (int)height);
    return;
    }   
    mSurfaceTexture = surfaceTexture;

// 内部通过SurfaceComposerClient,最终调用SurfaceFlinger来创建一个DisplayDeviceState,添加到

// DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL); –> 所有createDisplay均是DISPLAY_VIRTUAL类型

//mCurrentState.displays.add(token,info); 在SurfaceFlinger当中添加了一个显示设备,SurfaceFlinger就会将这些数据

// 写到这些显示设备上面
    mDisplayBinder = mComposerClient->createDisplay(
            String8("foo"), false /* secure */);

    SurfaceComposerClient::openGlobalTransaction();

// 修改内部DisplayState  定义在LayerState.h当中

// DisplayState &s(getDisplayStateLocked(token));

//s.surface = bufferProducer;

//s.what |= DisplayState::eSurfaceChanged;


    mComposerClient->setDisplaySurface(mDisplayBinder, mSurfaceTexture);

    //Rect layerStackRect(1280, 720);  // XXX fix this.
    Rect layerStackRect(width, height);  // XXX fix this.
    //Rect displayRect(1280, 720);
    Rect displayRect(width, height);

    mComposerClient->setDisplayProjection(
            mDisplayBinder, 0 /* 0 degree rotation */,
            layerStackRect,
            displayRect);

    SurfaceComposerClient::closeGlobalTransaction();
}

void RemoteDisplayClient::onDisplayDisconnected() {

    enableAudioSubmix(false /* enable */);
    //Mutex::Autolock autoLock(mLock);
    //mDone = true;
    ALOGD("onDisplayDisconnected");
    //mCondition.broadcast();
}

void RemoteDisplayClient::onDisplayError(int32_t error) {
    ALOGI("onDisplayError error=%d", error);

    Mutex::Autolock autoLock(mLock);
    mDone = true;
    mCondition.broadcast();
}

void RemoteDisplayClient::onRecordScreen(char *buffer, int len) {
    //JNIEnv* env = AndroidRuntime::getJNIEnv();
    JNIEnv* env = mEnv;
       jbyteArray data =  env->NewByteArray(len);
       env->SetByteArrayRegion(data, 0, len,
           reinterpret_cast<const jbyte*>(buffer));

    ALOGE("### onRecordScreen in android_media_RemoteDisplay.cpp ###");
       env->CallVoidMethod(mRemoteDisplayObjGlobal,
                gRemoteDisplayClassInfo.notifyRecordScreen, data, len);
       checkAndClearExceptionFromCallback(env, "notifyRecordScreen");
}

void RemoteDisplayClient::waitUntilDone() {
    Mutex::Autolock autoLock(mLock);
    while (!mDone) {
        mCondition.wait(mLock);
    }
}

class NativeRemoteDisplayEx {
public:
    NativeRemoteDisplayEx(const sp<IRemoteDisplay>& display,
            const sp<RemoteDisplayClient>& client) :
            mDisplay(display), mClient(client) {
    }

    ~NativeRemoteDisplayEx()
    {
    ALOGI("### ~NativeRemoteDisplayEx 01 ###");
        if(mDisplay != NULL)
        {
    ALOGI("### ~NativeRemoteDisplayEx 02 ###");
               mDisplay->dispose();
        }
        }

     void pauseRecord()
    {
    ALOGI("### pauseRecord 01 ###");
        if(mDisplay != NULL)
        {
    ALOGI("### pauseRecord 02 ###");
            mDisplay->pause();
        }
        }

     void resumeRecord()
    {
    ALOGI("### resumeRecord 01 ###");   
        if(mDisplay != NULL)
        {
    ALOGI("### resumeRecord 02 ###");   
                mDisplay->resume();
        }
        }

     void stopRecord()
    {
    ALOGI("### stopRecord 01 ###");   
        if(mDisplay != NULL)
        {
    ALOGI("### stopRecord 02 ###");   
                mDisplay->dispose();
        }
        }

private:
    sp<IRemoteDisplay> mDisplay;
    sp<RemoteDisplayClient> mClient;
};

static jint nativeStartRecord(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr) {
    ScopedUtfChars iface(env, ifaceStr);
    ALOGI("### nativeStartRecord ###");
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("media.player"));
    sp<IMediaPlayerService> service =
        interface_cast<IMediaPlayerService>(binder);

    CHECK(service.get() != NULL);

    enableAudioSubmix(true /* enable */);

    sp<RemoteDisplayClient> client = new RemoteDisplayClient(env, remoteDisplayObj);
    sp<IRemoteDisplay> display = service->listenForRemoteDisplay(client, String8(iface.c_str()));

#if 0 //{
    if(wrapper != NULL)
    {
        //delete wrapper;
        //wrapper = NULL;
    }
#endif //}   
      NativeRemoteDisplayEx* wrapper = new NativeRemoteDisplayEx(display, client);

    return reinterpret_cast<jint>(wrapper);
}

static jint nativePauseRecord(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
    ALOGI("### nativePauseRecord ###");
  NativeRemoteDisplayEx* wrapper = reinterpret_cast<NativeRemoteDisplayEx*>(ptr);
  wrapper->pauseRecord();
    return 0;
}

static jint nativeResumeRecord(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
    ALOGI("### nativeResumeRecord ###");
  NativeRemoteDisplayEx* wrapper = reinterpret_cast<NativeRemoteDisplayEx*>(ptr);
  wrapper->resumeRecord(); 
    return 0;
}

static jint nativeStopRecord(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
    ALOGI("### nativeStopRecord ###");
  NativeRemoteDisplayEx* wrapper = reinterpret_cast<NativeRemoteDisplayEx*>(ptr);  
    delete wrapper;
    //wrapper->stopRecord();
    return 0;
}

static jint nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr) {
    ScopedUtfChars iface(env, ifaceStr);

    sp<IServiceManager> sm = defaultServiceManager();
    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(
            sm->getService(String16("media.player")));
    if (service == NULL) {
        ALOGE("Could not obtain IMediaPlayerService from service manager");
        return 0;
    }

    sp<NativeRemoteDisplayClient> client(new NativeRemoteDisplayClient(env, remoteDisplayObj));
    sp<IRemoteDisplay> display = service->listenForRemoteDisplay(
            client, String8(iface.c_str()));
    if (display == NULL) {
        ALOGE("Media player service rejected request to listen for remote display '%s'.",
                iface.c_str());
        return 0;
    }

    NativeRemoteDisplay* wrapper = new NativeRemoteDisplay(display, client);
    return reinterpret_cast<jint>(wrapper);
}

static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
    NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
    delete wrapper;
}

// ----------------------------------------------------------------------------

static JNINativeMethod gMethods[] = {
    {"nativeListen", "(Ljava/lang/String;)I",
            (void*)nativeListen },
    {"nativeStartRecord", "(Ljava/lang/String;)I",
            (void*)nativeStartRecord },
    {"nativePauseRecord", "(I)I",
            (void*)nativePauseRecord },
    {"nativeResumeRecord", "(I)I",
            (void*)nativeResumeRecord },
    {"nativeStopRecord", "(I)I",
            (void*)nativeStopRecord },           
    {"nativeDispose", "(I)V",
            (void*)nativeDispose },
};

int register_android_media_RemoteDisplay(JNIEnv* env)
{
    int err = AndroidRuntime::registerNativeMethods(env, "android/media/RemoteDisplay",
            gMethods, NELEM(gMethods));

    jclass clazz = env->FindClass("android/media/RemoteDisplay");
    gRemoteDisplayClassInfo.notifyDisplayConnected =
            env->GetMethodID(clazz, "notifyDisplayConnected",
                    "(Landroid/view/Surface;III)V");
    gRemoteDisplayClassInfo.notifyDisplayDisconnected =
            env->GetMethodID(clazz, "notifyDisplayDisconnected", "()V");
    gRemoteDisplayClassInfo.notifyDisplayError =
            env->GetMethodID(clazz, "notifyDisplayError", "(I)V");
    gRemoteDisplayClassInfo.notifyRecordScreen =
            env->GetMethodID(clazz, "notifyRecordScreen", "([BI)V");   
    return err;
}

pizzaframeworksasecorejavaandroidhardwaredisplayIDisplayManager.aidl

  DisplayManager负责管理所有的Display对象,给JAVA用户负责使用的接口

// No permissions required.
void startScreenRecord(String outfile);

// No permissions required.
void pauseScreenRecord();

// No permissions required.
void resumeScreenRecord();

// No permissions required.
void stopScreenRecord();

// No permissions required.
boolean canRecordScreen();

// No permissions required.
boolean canUseWfd();

 

pizzaframeworksaseservicesjavacomandroidserverdisplayDisplayManagerService.java

   public void startScreenRecord(String outfile) {
        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mSyncRoot) {
                if (mWifiDisplayAdapter != null) {
                    mWifiDisplayAdapter.requestStartRecordScreenLocked(outfile);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override // Binder call
    public void pauseScreenRecord() {
        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mSyncRoot) {
                if (mWifiDisplayAdapter != null) {
                    mWifiDisplayAdapter.requestPauseRecordScreenLocked();
                }
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }
    @Override // Binder call
    public void resumeScreenRecord() {
        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mSyncRoot) {
                if (mWifiDisplayAdapter != null) {
                    mWifiDisplayAdapter.requestResumeRecordScreenLocked();
                }
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override // Binder call
    public void stopScreenRecord() {
        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mSyncRoot) {
                if (mWifiDisplayAdapter != null) {
                    mWifiDisplayAdapter.requestStopRecordScreenLocked();
                }
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override // Binder call
    public boolean canRecordScreen() {
        if (mWifiDisplayAdapter != null) {
            return mWifiDisplayAdapter.requestCanRecordScreenLocked();
        }
     return false;
    }

    @Override // Binder call
    public boolean canUseWfd() {
        if (mWifiDisplayAdapter != null) {
            return mWifiDisplayAdapter.requestCanUseWfdLocked();
        }
     return false;
    }

    @Override // Binder call

 

RemoteDisplay 其被有三个部分WifiDisplayAdapter,WifiDisplayController.java, WifiDisplayDevice集成起来使用。

pizzaframeworksaseservicesjavacomandroidserverdisplayWifiDisplayAdapter.java

       public void requestStartRecordScreenLocked(final String outfile) {
        if (DEBUG) {
            Slog.d(TAG, "requestStartRecordScreenLocked");
        }

        getHandler().post(new Runnable() {
            @Override
            public void run() {
                if (mDisplayController != null) {
                    mDisplayController.requestStartRecordScreen(outfile);
                }
            }
        });
    }

       public void requestPauseRecordScreenLocked() {
        if (DEBUG) {
            Slog.d(TAG, "requestPauseRecordScreenLocked");
        }

        getHandler().post(new Runnable() {
            @Override
            public void run() {
                if (mDisplayController != null) {
                    mDisplayController.requestPauseRecordScreen();
                }
            }
        });
    }

       public void requestResumeRecordScreenLocked() {
        if (DEBUG) {
            Slog.d(TAG, "requestResumeRecordScreenLocked");
        }

        getHandler().post(new Runnable() {
            @Override
            public void run() {
                if (mDisplayController != null) {
                    mDisplayController.requestResumeRecordScreen();
                }
            }
        });
    }

       public void requestStopRecordScreenLocked() {
        if (DEBUG) {
            Slog.d(TAG, "requestStopRecordScreenLocked");
        }

        getHandler().post(new Runnable() {
            @Override
            public void run() {
                if (mDisplayController != null) {
                    mDisplayController.requestStopRecordScreen();
                }
            }
        });
    }

       public boolean requestCanRecordScreenLocked() {
                if (mDisplayController != null) {
                    return mDisplayController.requestCanRecordScreen();
                }
          return false;
    }

       public boolean requestCanUseWfdLocked() {
                if (mDisplayController != null) {
                    return mDisplayController.requestCanUseWfd();
                }
          return false;
    }

pizzaframeworksaseservicesjavacomandroidserverdisplayWifiDisplayController.java

private static final int RECSCR_STATUS_UNKNOWN = -1;
private static final int RECSCR_STATUS_RECORDING = 1;
private static final int RECSCR_STATUS_PAUSED = 2;
private static final int RECSCR_STATUS_STOPPED = 3;   

private RemoteDisplay mRecordScreen;

    public void requestStartRecordScreen(String outfile) {
        if(RECSCR_STATUS_UNKNOWN == mRecordStatus || RECSCR_STATUS_STOPPED == mRecordStatus)
        {
            if(mRemoteDisplay != null)
            {
                Slog.e(TAG, "### requestStartRecordScreen mRemoteDisplay != null ###");
                return;
            }
            Slog.d(TAG, "### requestStartRecordScreen outfile: " + outfile + " ###");
                mRecordScreen = RemoteDisplay.recordScreen(outfile, new RemoteDisplay.Listener() {
                        @Override
                        public void onDisplayConnected(Surface surface,
                                int width, int height, int flags) {
                            Slog.d(TAG, "### onDisplayConnected ###");
                        }

                        @Override
                        public void onDisplayDisconnected() {
                               Slog.d(TAG, "### onDisplayDisconnected ###");
                        }

                        @Override
                        public void onDisplayError(int error) {
                            Slog.d(TAG, "### onDisplayError ###");                       
                        }

                        @Override
                        public void onRecordScreen(byte[] buffer, int len) {
                            Slog.d(TAG, "### onRecordScreen ###");
                        }
                    }, mHandler);
                mHandler.postDelayed(mRtspTimeout, RTSP_TIMEOUT_SECONDS * 1000  * 1000);
        mRecordStatus = RECSCR_STATUS_RECORDING;
        }
    }

    public void requestPauseRecordScreen() {
        if(RECSCR_STATUS_RECORDING == mRecordStatus && mRecordScreen != null)
        {
            Slog.d(TAG, "### requestPauseRecordScreen ###");
            mRecordScreen.pauseRecording();
            mRecordStatus = RECSCR_STATUS_PAUSED;
        }
    }

    public void requestResumeRecordScreen() {
        if(RECSCR_STATUS_PAUSED == mRecordStatus && mRecordScreen != null)
        {
            Slog.d(TAG, "### requestResumeRecordScreen ###");
            mRecordScreen.resumeRecording();
            mRecordStatus = RECSCR_STATUS_RECORDING;
        }
    }

    public void requestStopRecordScreen() {
        if(RECSCR_STATUS_RECORDING == mRecordStatus && mRecordScreen != null)
        {
            Slog.d(TAG, "### requestStopRecordScreen ###");
            mRecordScreen.stopRecording();
            mRecordStatus = RECSCR_STATUS_STOPPED;
            mRecordScreen = null;
        }       
    }

    public boolean requestCanRecordScreen() {
        Slog.d(TAG, "### requestCanRecordScreen ###");
        if(mRemoteDisplay == null)
        {
            Slog.d(TAG, "### requestCanRecordScreen true ###");
            return true;
        }
        return false;
    }

    public boolean requestCanUseWfd() {
        Slog.d(TAG, "### requestCanUseWfd ###");
        if(mRecordScreen == null)
        {
            Slog.d(TAG, "### requestCanUseWfd true ###");
            return true;
        }
        return false;
    }

原文地址:https://www.cnblogs.com/pengxinglove/p/5550933.html