summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2013-12-02 16:30:50 -0800
committerDianne Hackborn <hackbod@google.com>2013-12-04 16:10:30 -0800
commit18159037a4f6a6b539736f6b8c0bdab4d26e3bd7 (patch)
tree6b2d8398f89d6b54b556cd88ff49b3d76fc87822
parent3519ce6eb348ac43536879bc94aacdea065df750 (diff)
downloaddevelopment-android-sdk-4.4.2_r1.tar.gz
Add API demo for game style system UI interaction.android-sdk-4.4.2_r1.0.1android-sdk-4.4.2_r1
Shows the ideal way for a game to interact with system UI, hiding the status bar and nav bar while being played, making them visible when paused or otherwise interacting with controls of the game, and determing layout of game controls to not be covered by the status bar or nav bar. Change-Id: Ia192c31321113d81f96c06c7a69a06ef72c4682a
-rw-r--r--samples/ApiDemos/AndroidManifest.xml10
-rw-r--r--samples/ApiDemos/res/layout/game.xml48
-rw-r--r--samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java57
-rw-r--r--samples/ApiDemos/src/com/example/android/apis/view/GameActivity.java189
4 files changed, 292 insertions, 12 deletions
diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml
index d7bda3125..f202d595d 100644
--- a/samples/ApiDemos/AndroidManifest.xml
+++ b/samples/ApiDemos/AndroidManifest.xml
@@ -2469,6 +2469,16 @@
</intent-filter>
</activity>
+ <activity android:name=".view.GameActivity"
+ android:label="Views/System UI Visibility/Game"
+ android:theme="@android:style/Theme.Holo.NoActionBar"
+ android:enabled="@bool/atLeastKitKat">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
<activity android:name=".view.Switches" android:label="Views/Switches">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/samples/ApiDemos/res/layout/game.xml b/samples/ApiDemos/res/layout/game.xml
new file mode 100644
index 000000000..809a253c1
--- /dev/null
+++ b/samples/ApiDemos/res/layout/game.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<!-- BEGIN_INCLUDE(complete) -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent" android:layout_height="match_parent"
+ >
+ <!-- This is the outer area of the entire game screen, extending out under
+ system UI elements. -->
+ <view class="com.example.android.apis.view.GameActivity$Content"
+ android:id="@+id/content"
+ android:src="@drawable/frantic"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="center"
+ />
+ <!-- This is the inner area of the game, not covered by system UI elements.
+ Any UI elements that need to be accessible when the game is paused or other
+ states where the system UI is shown (such as in menus) should go here. -->
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true"
+ android:animateLayoutChanges="true"
+ >
+ <Button
+ android:id="@+id/play"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|right"
+ android:textSize="28dp"
+ />
+ </FrameLayout>
+</FrameLayout>
+<!-- END_INCLUDE(complete) -->
diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java b/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java
index c3c8a6cc3..a86301415 100644
--- a/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java
+++ b/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java
@@ -26,6 +26,7 @@ import android.graphics.RectF;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.util.AttributeSet;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
@@ -87,9 +88,6 @@ public class TouchPaint extends GraphicsActivity {
/** Is fading mode enabled? */
boolean mFading;
- /** The index of the current color to use. */
- int mColorIndex;
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -104,10 +102,10 @@ public class TouchPaint extends GraphicsActivity {
// the contents of the bitmap.
if (savedInstanceState != null) {
mFading = savedInstanceState.getBoolean("fading", true);
- mColorIndex = savedInstanceState.getInt("color", 0);
+ mView.mColorIndex = savedInstanceState.getInt("color", 0);
} else {
mFading = true;
- mColorIndex = 0;
+ mView.mColorIndex = 0;
}
}
@@ -161,7 +159,7 @@ public class TouchPaint extends GraphicsActivity {
// Save away the fading state to restore if needed later. Note that
// we do not currently save the contents of the display.
outState.putBoolean("fading", mFading);
- outState.putInt("color", mColorIndex);
+ outState.putInt("color", mView.mColorIndex);
}
@Override
@@ -225,9 +223,9 @@ public class TouchPaint extends GraphicsActivity {
*
* It handles all of the input events and drawing functions.
*/
- class PaintView extends View {
+ public static class PaintView extends View {
private static final int FADE_ALPHA = 0x06;
- private static final int MAX_FADE_STEPS = 256 / FADE_ALPHA + 4;
+ private static final int MAX_FADE_STEPS = 256 / (FADE_ALPHA/2) + 4;
private static final int TRACKBALL_SCALE = 10;
private static final int SPLAT_VECTORS = 40;
@@ -235,21 +233,31 @@ public class TouchPaint extends GraphicsActivity {
private final Random mRandom = new Random();
private Bitmap mBitmap;
private Canvas mCanvas;
- private final Paint mPaint;
- private final Paint mFadePaint;
+ private final Paint mPaint = new Paint();
+ private final Paint mFadePaint = new Paint();
private float mCurX;
private float mCurY;
private int mOldButtonState;
private int mFadeSteps = MAX_FADE_STEPS;
+ /** The index of the current color to use. */
+ int mColorIndex;
+
public PaintView(Context c) {
super(c);
+ init();
+ }
+
+ public PaintView(Context c, AttributeSet attrs) {
+ super(c, attrs);
+ init();
+ }
+
+ private void init() {
setFocusable(true);
- mPaint = new Paint();
mPaint.setAntiAlias(true);
- mFadePaint = new Paint();
mFadePaint.setColor(BACKGROUND_COLOR);
mFadePaint.setAlpha(FADE_ALPHA);
}
@@ -273,6 +281,31 @@ public class TouchPaint extends GraphicsActivity {
}
}
+ public void text(String text) {
+ if (mBitmap != null) {
+ final int width = mBitmap.getWidth();
+ final int height = mBitmap.getHeight();
+ mPaint.setColor(COLORS[mColorIndex]);
+ mPaint.setAlpha(255);
+ int size = height;
+ mPaint.setTextSize(size);
+ Rect bounds = new Rect();
+ mPaint.getTextBounds(text, 0, text.length(), bounds);
+ int twidth = bounds.width();
+ twidth += (twidth/4);
+ if (twidth > width) {
+ size = (size*width)/twidth;
+ mPaint.setTextSize(size);
+ mPaint.getTextBounds(text, 0, text.length(), bounds);
+ }
+ Paint.FontMetrics fm = mPaint.getFontMetrics();
+ mCanvas.drawText(text, (width-bounds.width())/2,
+ ((height-size)/2) - fm.ascent, mPaint);
+ mFadeSteps = 0;
+ invalidate();
+ }
+ }
+
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
int curW = mBitmap != null ? mBitmap.getWidth() : 0;
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/GameActivity.java b/samples/ApiDemos/src/com/example/android/apis/view/GameActivity.java
new file mode 100644
index 000000000..a02542707
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/GameActivity.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2011 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.example.android.apis.view;
+
+import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.Activity;
+import android.app.FragmentTransaction;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.SearchView;
+import android.widget.SeekBar;
+import android.widget.ShareActionProvider;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.SearchView.OnQueryTextListener;
+
+import com.example.android.apis.R;
+import com.example.android.apis.graphics.TouchPaint;
+
+/**
+ * This activity demonstrates how to use the system UI flags to
+ * implement an immersive game.
+ */
+public class GameActivity extends Activity {
+
+ /**
+ * Implementation of a view for the game, filling the entire screen.
+ */
+//BEGIN_INCLUDE(content)
+ public static class Content extends TouchPaint.PaintView implements
+ View.OnSystemUiVisibilityChangeListener, View.OnClickListener {
+ Activity mActivity;
+ Button mPlayButton;
+ boolean mPaused;
+ int mLastSystemUiVis;
+ boolean mUpdateSystemUi;
+
+ Runnable mFader = new Runnable() {
+ @Override public void run() {
+ fade();
+ if (mUpdateSystemUi) {
+ updateNavVisibility();
+ }
+ if (!mPaused) {
+ getHandler().postDelayed(mFader, 1000/30);
+ }
+ }
+ };
+
+ public Content(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setOnSystemUiVisibilityChangeListener(this);
+ }
+
+ public void init(Activity activity, Button playButton) {
+ // This called by the containing activity to supply the surrounding
+ // state of the game that it will interact with.
+ mActivity = activity;
+ mPlayButton = playButton;
+ mPlayButton.setOnClickListener(this);
+ setGamePaused(true);
+ }
+
+ @Override public void onSystemUiVisibilityChange(int visibility) {
+ // Detect when we go out of nav-hidden mode, to reset back to having
+ // it hidden; our game wants those elements to stay hidden as long
+ // as it is being played and stay shown when paused.
+ int diff = mLastSystemUiVis ^ visibility;
+ mLastSystemUiVis = visibility;
+ if (!mPaused && (diff&SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
+ && (visibility&SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
+ // We are running and the system UI navigation has become
+ // shown... we want it to remain hidden, so update our system
+ // UI state at the next game loop.
+ mUpdateSystemUi = true;
+ }
+ }
+
+ @Override protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+
+ // When we become visible or invisible, play is paused.
+ setGamePaused(true);
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ super.onWindowFocusChanged(hasWindowFocus);
+
+ // When we become visible or invisible, play is paused.
+ // Optional: pause game when window loses focus. This will cause it to
+ // pause, for example, when the notification shade is pulled down.
+ if (!hasWindowFocus) {
+ //setGamePaused(true);
+ }
+ }
+
+ @Override public void onClick(View v) {
+ if (v == mPlayButton) {
+ // Clicking on the play/pause button toggles its state.
+ setGamePaused(!mPaused);
+ }
+ }
+
+ void setGamePaused(boolean paused) {
+ mPaused = paused;
+ mPlayButton.setText(paused ? R.string.play : R.string.pause);
+ setKeepScreenOn(!paused);
+ updateNavVisibility();
+ Handler h = getHandler();
+ if (h != null) {
+ getHandler().removeCallbacks(mFader);
+ if (!paused) {
+ mFader.run();
+ text("Draw!");
+ }
+ }
+ }
+
+ void updateNavVisibility() {
+ int newVis = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | SYSTEM_UI_FLAG_LAYOUT_STABLE;
+ if (!mPaused) {
+ newVis |= SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_FULLSCREEN
+ | SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ }
+
+ // Set the new desired visibility.
+ setSystemUiVisibility(newVis);
+ mUpdateSystemUi = false;
+ }
+ }
+//END_INCLUDE(content)
+
+ Content mContent;
+
+ public GameActivity() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.game);
+ mContent = (Content)findViewById(R.id.content);
+ mContent.init(this, (Button)findViewById(R.id.play));
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ // Pause game when its activity is paused.
+ mContent.setGamePaused(true);
+ }
+}