Back to project page gdk-level-sample.
The source code is released under:
Apache License
If you think the Android project gdk-level-sample listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* * Copyright (C) 2013 Google Inc.//from w w w . ja va 2s . co m * * 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.google.android.glass.sample.level; import android.content.Context; import android.graphics.Canvas; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.SystemClock; import android.util.Log; import android.view.LayoutInflater; import android.view.SurfaceHolder; import android.view.View; import android.widget.FrameLayout; import com.google.android.glass.timeline.DirectRenderingCallback; import java.util.concurrent.TimeUnit; public class LevelRenderer implements DirectRenderingCallback { private static final String TAG = LevelRenderer.class.getSimpleName(); /** The refresh rate, in frames per second, of the Live Card. */ private static final int REFRESH_RATE_FPS = 33; /** The duration, in milliseconds, of one frame. */ private static final long FRAME_TIME_MILLIS = TimeUnit.SECONDS.toMillis(1) / REFRESH_RATE_FPS; private SurfaceHolder mHolder; private RenderThread mRenderThread; private SensorManager mSensorManager; private int mSurfaceWidth; private int mSurfaceHeight; private boolean mRenderingPaused; private final FrameLayout mLayout; private final LevelView mLevelView; private final SensorEventListener mSensorEventListener = new SensorEventListener() { @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // Nothing to do here. } @Override public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_GRAVITY) { computeOrientation(event); } } /** * Compute the orientation angle. * * @param event Gravity values. */ private void computeOrientation(SensorEvent event) { float angle = (float) -Math.atan(event.values[0] / Math.sqrt(event.values[1] * event.values[1] + event.values[2] * event.values[2])); mLevelView.setAngle(angle); } }; /** * Creates a new instance of the {@code LevelRenderer} . */ public LevelRenderer(SensorManager sensorManager, Context context) { LayoutInflater inflater = LayoutInflater.from(context); mLayout = (FrameLayout) inflater.inflate(R.layout.level_live_card, null); mLevelView = (LevelView) mLayout.findViewById(R.id.level); mSensorManager = sensorManager; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { mSurfaceWidth = width; mSurfaceHeight = height; doLayout(); } @Override public void surfaceCreated(SurfaceHolder holder) { mHolder = holder; updateRenderingState(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { mHolder = null; updateRenderingState(); } @Override public void renderingPaused(SurfaceHolder surfaceHolder, boolean paused) { mRenderingPaused = paused; updateRenderingState(); } /** * Starts or stops rendering according to the {@link LiveCard}'s state. */ private void updateRenderingState() { boolean shouldRender = (mHolder != null) && !mRenderingPaused; boolean isRendering = (mRenderThread != null); if (shouldRender != isRendering) { if (shouldRender) { mSensorManager.registerListener(mSensorEventListener, mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY), SensorManager.SENSOR_DELAY_NORMAL); mRenderThread = new RenderThread(); mRenderThread.start(); } else { mRenderThread.quit(); mRenderThread = null; mSensorManager.unregisterListener(mSensorEventListener); } } } /** * Requests that the views redo their layout. This must be called manually every time the * tips view's text is updated because this layout doesn't exist in a GUI thread where those * requests will be enqueued automatically. */ private void doLayout() { // Measure and update the layout so that it will take up the entire surface space // when it is drawn. int measuredWidth = View.MeasureSpec.makeMeasureSpec(mSurfaceWidth, View.MeasureSpec.EXACTLY); int measuredHeight = View.MeasureSpec.makeMeasureSpec(mSurfaceHeight, View.MeasureSpec.EXACTLY); mLayout.measure(measuredWidth, measuredHeight); mLayout.layout(0, 0, mLayout.getMeasuredWidth(), mLayout.getMeasuredHeight()); } /** * Repaints the Live Card. */ private synchronized void repaint() { Canvas canvas = null; try { canvas = mHolder.lockCanvas(); } catch (RuntimeException e) { Log.d(TAG, "lockCanvas failed", e); } if (canvas != null) { doLayout(); mLayout.draw(canvas); try { mHolder.unlockCanvasAndPost(canvas); } catch (RuntimeException e) { Log.d(TAG, "unlockCanvasAndPost failed", e); } } } /** * Redraws the Live Card in the background. */ private class RenderThread extends Thread { private boolean mShouldRun; /** * Initializes the background rendering thread. */ public RenderThread() { mShouldRun = true; } /** * Returns true if the rendering thread should continue to run. * * @return true if the rendering thread should continue to run */ private synchronized boolean shouldRun() { return mShouldRun; } /** * Requests that the rendering thread exit at the next opportunity. */ public synchronized void quit() { mShouldRun = false; } @Override public void run() { while (shouldRun()) { long frameStart = SystemClock.elapsedRealtime(); repaint(); long frameLength = SystemClock.elapsedRealtime() - frameStart; long sleepTime = FRAME_TIME_MILLIS - frameLength; if (sleepTime > 0) { SystemClock.sleep(sleepTime); } } } } }