/**
 * Copyright 2011 The PlayN Authors
 *
 * 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 playn.android;

import java.io.File;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.widget.LinearLayout;

import playn.core.PlayN;

/**
 * TODO: save/restore state
 */
public abstract class GameActivity extends Activity {

  private final int REQUIRED_CONFIG_CHANGES =
    ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;

  private AndroidPlatform platform;
  private GameViewGL gameView;
  private KeyEventHandler keyHandler;
  private TouchEventHandler touchHandler;

  /**
   * The entry-point into a PlayN game. Developers should implement main() to call
   * platform().assets().setPathPrefix() and PlayN.run().
   */
  public abstract void main();

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Build the AndroidPlatform and register this activity.
    Context appctx = getApplicationContext();
    AndroidGL20 gl20 = (isHoneycombOrLater() || !AndroidGL20Native.available) ?
      new AndroidGL20() :      // uses platform methods for everything
      new AndroidGL20Native(); // uses our own native bindings for some missing methods
    this.platform = new AndroidPlatform(this, gl20);
    this.gameView = new GameViewGL(appctx, platform, gl20);
    this.keyHandler = new KeyEventHandler(platform);
    this.touchHandler = new TouchEventHandler(platform);
    PlayN.setPlatform(platform);

    // Build the Window and View
    int windowFlags = WindowManager.LayoutParams.FLAG_FULLSCREEN;
    if (isHoneycombOrLater()) {
      // Use the raw constant rather than the flag to avoid blowing up on earlier Android
      windowFlags |= 0x1000000; // flagHardwareAccelerated
    }
    getWindow().setFlags(windowFlags, windowFlags);

    // Create our layout and configure the window.
    setContentView(gameView);

    // Default to landscape orientation.
    if (usePortraitOrientation()) {
      setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    } else {
      setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    }

    // Make sure the AndroidManifest.xml is set up correctly.
    try {
      ActivityInfo info = this.getPackageManager().getActivityInfo(
          new ComponentName(appctx, this.getPackageName() + "." + this.getLocalClassName()), 0);
      if ((info.configChanges & REQUIRED_CONFIG_CHANGES) != REQUIRED_CONFIG_CHANGES) {
        new AlertDialog.Builder(this).setMessage(
            "Unable to guarantee application will handle configuration changes. "
                + "Please add the following line to the Activity manifest: "
                + "      android:configChanges=\"keyboardHidden|orientation\"").show();
      }
    } catch (NameNotFoundException e) {
      platform.log().warn("Cannot access game AndroidManifest.xml file.");
    }
  }

  /**
   * Determines whether or not a game should run in portrait orientation or not.
   * Defaults to false. Override this method to return true to use portrait.
   *
   * @return Whether or not the game will run in portrait orientation
   */
  public boolean usePortraitOrientation() {
    return false;
  }

  protected float scaleFactor() {
    return 1; // TODO: determine scale factor automatically?
  }

  public GameViewGL gameView() {
    return gameView;
  }

  boolean isHoneycombOrLater() {
    return android.os.Build.VERSION.SDK_INT >= 11;
  }

  protected AndroidPlatform platform() {
    return platform;
  }

  protected void setContentView(GameViewGL view) {
    LinearLayout layout = new LinearLayout(this);
    layout.setBackgroundColor(0xFF000000);
    layout.setGravity(Gravity.CENTER);
    layout.addView(gameView);
    LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
    getWindow().setContentView(layout, params);
  }

  @Override
  protected void onDestroy() {
    AndroidPlatform.debugLog("onDestroy");
    for (File file : getCacheDir().listFiles()) {
      file.delete();
    }
    platform.audio().onDestroy();
    platform.onExit();
    super.onDestroy();
  }

  @Override
  protected void onPause() {
    AndroidPlatform.debugLog("onPause");
    gameView.onPause();
    // TODO: we should really wait for the renderer to stop here, because otherwise
    // Platform.onPause could be racing with one final frame on the GL thread; however I've seen
    // scary things about deadlock and other crap by people who have tried to do this "correctly"
    platform.onPause();
    platform.audio().onPause();
    super.onPause();
  }

  @Override
  protected void onResume() {
    AndroidPlatform.debugLog("onResume");
    // since the GL thread is not running, we go ahead and run these onResumes on the UI thread,
    // then resume the GL thread as our last action
    platform.audio().onResume();
    platform.onResume();
    gameView.onResume();
    super.onResume();
  }

  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
    keyHandler.onKeyDown(keyCode, event);
    return super.onKeyDown(keyCode, event);
  }

  @Override
  public boolean onKeyUp(int keyCode, KeyEvent event) {
    keyHandler.onKeyUp(keyCode, event);
    return super.onKeyUp(keyCode, event);
  }

  /**
   * Called automatically to handle touch events. Queues the touch events to be processed on the
   * game thread.
   */
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    touchHandler.onMotionEvent(event);
    return super.onTouchEvent(event);
  }
}

@@ -3828,24 +3828,100 @@
 %0A    %7D%0A  %7D%0A%0A
+  @Override%0A  public void onBackPressed() %7B%0A    moveTaskToBack(false);%0A  %7D%0A%0A
   /**%0A   * D
@@ -3994,21 +3994,16 @@
  or not.
-%0A   *
  Default
@@ -4013,16 +4013,21 @@
 o false.
+%0A   *
  Overrid
@@ -4152,29 +4152,32 @@
 on%0A   */%0A  p
-ublic
+rotected
  boolean use

Move our task to the back of the stack onBackPressed.