AppRTCDemo(android): support app (UI) & capture rotation.

Now app UI rotates as the device orientation changes, and the captured stream
tries to maintain real-world-up, matching Chrome/Android and Hangouts/Android
behavior.

BUG=2432
R=glaznev@webrtc.org, henrike@webrtc.org, wu@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/15689005

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@6354 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/video_capture/android/video_capture_android.cc b/modules/video_capture/android/video_capture_android.cc
index f42329e..2ecac2e 100644
--- a/modules/video_capture/android/video_capture_android.cc
+++ b/modules/video_capture/android/video_capture_android.cc
@@ -19,9 +19,16 @@
 
 static JavaVM* g_jvm = NULL;
 static jclass g_java_capturer_class = NULL;  // VideoCaptureAndroid.class.
+static jobject g_context = NULL;  // Owned android.content.Context.
 
 namespace webrtc {
 
+// Called by Java to get the global application context.
+jobject JNICALL GetContext(JNIEnv* env, jclass) {
+  assert(g_context);
+  return g_context;
+}
+
 // Called by Java when the camera has a new frame to deliver.
 void JNICALL ProvideCameraFrame(
     JNIEnv* env,
@@ -38,11 +45,31 @@
   env->ReleaseByteArrayElements(javaCameraFrame, cameraFrame, JNI_ABORT);
 }
 
-int32_t SetCaptureAndroidVM(JavaVM* javaVM) {
+// Called by Java when the device orientation has changed.
+void JNICALL OnOrientationChanged(
+    JNIEnv* env, jobject, jlong context, jint degrees) {
+  webrtc::videocapturemodule::VideoCaptureAndroid* captureModule =
+      reinterpret_cast<webrtc::videocapturemodule::VideoCaptureAndroid*>(
+          context);
+  degrees = (360 + degrees) % 360;
+  assert(degrees >= 0 && degrees < 360);
+  VideoCaptureRotation rotation =
+      (degrees <= 45 || degrees > 315) ? kCameraRotate0 :
+      (degrees > 45 && degrees <= 135) ? kCameraRotate90 :
+      (degrees > 135 && degrees <= 225) ? kCameraRotate180 :
+      (degrees > 225 && degrees <= 315) ? kCameraRotate270 :
+      kCameraRotate0;  // Impossible.
+  int32_t status =
+      captureModule->VideoCaptureImpl::SetCaptureRotation(rotation);
+  assert(status == 0);
+}
+
+int32_t SetCaptureAndroidVM(JavaVM* javaVM, jobject context) {
   if (javaVM) {
     assert(!g_jvm);
     g_jvm = javaVM;
     AttachThreadScoped ats(g_jvm);
+    g_context = ats.env()->NewGlobalRef(context);
 
     videocapturemodule::DeviceInfoAndroid::Initialize(ats.env());
 
@@ -53,12 +80,18 @@
         reinterpret_cast<jclass>(ats.env()->NewGlobalRef(j_capture_class));
     assert(g_java_capturer_class);
 
-    JNINativeMethod native_method = {
-      "ProvideCameraFrame", "([BIJ)V",
-      reinterpret_cast<void*>(&ProvideCameraFrame)
-    };
+    JNINativeMethod native_methods[] = {
+        {"GetContext",
+         "()Landroid/content/Context;",
+         reinterpret_cast<void*>(&GetContext)},
+        {"OnOrientationChanged",
+         "(JI)V",
+         reinterpret_cast<void*>(&OnOrientationChanged)},
+        {"ProvideCameraFrame",
+         "([BIJ)V",
+         reinterpret_cast<void*>(&ProvideCameraFrame)}};
     if (ats.env()->RegisterNatives(g_java_capturer_class,
-                                   &native_method, 1) != 0)
+                                   native_methods, 3) != 0)
       assert(false);
   } else {
     if (g_jvm) {
@@ -66,6 +99,8 @@
       ats.env()->UnregisterNatives(g_java_capturer_class);
       ats.env()->DeleteGlobalRef(g_java_capturer_class);
       g_java_capturer_class = NULL;
+      ats.env()->DeleteGlobalRef(g_context);
+      g_context = NULL;
       videocapturemodule::DeviceInfoAndroid::DeInitialize();
       g_jvm = NULL;
     }
@@ -198,8 +233,9 @@
 int32_t VideoCaptureAndroid::SetCaptureRotation(
     VideoCaptureRotation rotation) {
   CriticalSectionScoped cs(&_apiCs);
-  if (VideoCaptureImpl::SetCaptureRotation(rotation) != 0)
-    return 0;
+  int32_t status = VideoCaptureImpl::SetCaptureRotation(rotation);
+  if (status != 0)
+    return status;
 
   AttachThreadScoped ats(g_jvm);
   JNIEnv* env = ats.env();