Android Wear - Sizuha/devdog GitHub Wiki

https://gist.github.com/JaeWoongOh/f3390a9c82718050813e

Debug

http://qiita.com/tnj/items/83c41872125f01588068

Bluetooth ใงใƒ‡ใƒใƒƒใ‚ฐๆŽฅ็ถšใ™ใ‚‹

Android Wear Device์—์„œ:

  1. Watch๋ฅผ ์ผœ๊ณ  ์„ค์ • > ์ •๋ณด > ๋นŒ๋“œ๋ฒˆํ˜ธํ•ญ๋ชฉ์„ ์—ฐํƒ€ํ•˜๊ฒŒ๋˜๋ฉด ์„ค์ • ๋ฉ”๋‰ด์— ๊ฐœ๋ฐœ์ž ์˜ต์…˜์ด ์ƒ๊ธฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  2. ๊ฐœ๋ฐœ์ž ์˜ต์…˜์œผ๋กœ ๋“ค์–ด๊ฐ€ ๋ณด๋ฉด ๋ธ”๋ฃจํˆฌ์Šค ์Šค๋ˆ„ํ”„๋กœ๊น…, ADB๋””๋ฒ„๊น…, ๋ธ”๋ฃจํˆฌ์— ๋Œ€ํ•œ ๋””๋ฒ„๊ทธ ํ•ญ๋ชฉ์ด ์žˆ๋Š”๋ฐ ๋ชจ๋‘ ์‚ฌ์šฉ์œผ๋กœ ์ฒดํฌ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.

Android Device์— ์—ฐ๊ฒฐ๋œ PC์—์„œ:

$ ./adb forward tcp:4444 localabstract:/adb-hub
$ ./adb connect localhost:4444
connected to localhost:4444

ใ“ใ‚Œใงใ€ ใƒ›ใ‚นใƒˆ: ๆŽฅ็ถšๆธˆใฟ ใจใชใ‚Šใ€ใ‚ใจใฏ USB ใง็น‹ใ„ใงใ„ใ‚‹ใฎใจๅŒใ˜ใ‚ˆใ†ใซ LogCat ใฎ่กจ็คบใŒๅฏ่ƒฝใซใชใ‚Šใพใ™ใ€‚ใŸใ ใ—ใ€ Bluetooth ๆŽฅ็ถšใชใฎใงใ€ใƒ•ใ‚กใ‚คใƒซใ‚„็”ป้ขใฎ่ปข้€ใซใฏ็ตๆง‹ๆ™‚้–“ใŒๆŽ›ใ‹ใ‚Šใพใ™ใ€‚ใ‚ใ‚“ใพใ‚Šๆฐ—่ปฝใซไฝฟใˆใ‚‹ใฃใฆๆ„Ÿใ˜ใงใฏใชใ•ใใ†ใงใ™ใ€‚

๋ฐฐํฌ ๋ฐฉ๋ฒ•

์•„์ง๊นŒ์ง€ ๋‹จ๋…์œผ๋กœ Android Wear ์•ฑ์„ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜๋‹จ์ด ์—†๋‹ค. ๋”ฐ๋ผ์„œ, ์ผ๋ฐ˜ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ์— Wear ์•ฑ์„ ํฌํ•จ์‹œ์ผœ์„œ ํ•จ๊ป˜ ๋ฐฐํฌํ•ด์•ผ๋งŒ ํ•œ๋‹ค.

์ฐธ๊ณ 

\1. wearable ์•ฑ์˜ apk ํŒŒ์ผ์„ mobile ์•ฑ์˜ res > raw ํด๋”์— ๋ณต์‚ฌ

\2. mobile ์•ฑ์˜ res > xml > ํด๋”์— ์ž„์˜์˜ .xml ํŒŒ์ผ์„ ์ƒ์„ฑ. (ex. wear_app.xml)

\3. wear_app.xmlํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํŽธ์ง‘.

<?xml version="1.0" encoding="utf-8"?>
<wearableApp package="ํ•ด๋‹น ์•ฑ์˜ ํŒจํ‚ค์ง€๋ช…">
    <versionCode>1</versionCode>    <!-- ๋ฐ˜๋“œ์‹œ ๋‘ ์•ฑ์˜ ๋ฒ„์ „์ฝ”๋“œ๊ฐ€ ์ผ์น˜ํ•ด์•ผ ํ•จ -->
    <versionName>1.0</versionName>    <!-- ๋‘ ์•ฑ์˜ ๋ฒ„์ „๋ช…์ด ์ผ์น˜ํ•ด์•ผ ํ•จ -->
    <rawPathResId>wear</rawPathResId>   <!-- wearable ์•ฑ apk ํŒŒ์ผ๋ช…(์ด๋ฆ„ ๋ถ€๋ถ„๋งŒ) -->
</wearableApp>
</source>    
4. mobile ์•ฑ์˜ AndroidManifest.xml ํŒŒ์ผ์˜ application ํƒœ๊ทธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‚ด์šฉ์„ ์ถ”๊ฐ€.
<source lang="xml">
        <meta-data
            android:name="com.google.android.wearable.beta.app"
            android:resource="@xml/wear_app" /> <!-- ์•ž์„œ ์ƒ์„ฑํ•œ xml -->

Sample

Watch

์•„๋‚ ๋กœ๊ทธ ์‹œ๊ณ„ ์ƒ˜ํ”Œ.

/**
 * Analog watch face with a ticking second hand. In ambient mode, the second hand isn't shown. On
 * devices with low-bit ambient mode, the hands are drawn without anti-aliasing in ambient mode.
 */
public class MyWatchFace extends CanvasWatchFaceService {
    /**
     * Update rate in milliseconds for interactive mode. We update once a second to advance the
     * second hand.
     */
    private static final long INTERACTIVE_UPDATE_RATE_MS = TimeUnit.SECONDS.toMillis(1);

    private Bitmap mBackgroundImg;
    private Bitmap mNeedleHour, mNeedleMin, mNeedleSec;


    @Override
    public Engine onCreateEngine() {
        return new Engine();
    }

    private class Engine extends CanvasWatchFaceService.Engine {
        static final int MSG_UPDATE_TIME = 0;

        Paint mBackgroundPaint;
        boolean mAmbient;
        Time mTime;

        /**
         * Handler to update the time once a second in interactive mode.
         */
        final Handler mUpdateTimeHandler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                switch (message.what) {
                    case MSG_UPDATE_TIME:
                        invalidate();
                        if (shouldTimerBeRunning()) {
                            long timeMs = System.currentTimeMillis();
                            long delayMs = INTERACTIVE_UPDATE_RATE_MS
                                    - (timeMs % INTERACTIVE_UPDATE_RATE_MS);
                            mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
                        }
                        break;
                }
            }
        };

        final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                mTime.clear(intent.getStringExtra("time-zone"));
                mTime.setToNow();
            }
        };
        boolean mRegisteredTimeZoneReceiver = false;

        /**
         * Whether the display supports fewer bits for each color in ambient mode. When true, we
         * disable anti-aliasing in ambient mode.
         */
        boolean mLowBitAmbient;

        @Override
        public void onCreate(SurfaceHolder holder) {
            super.onCreate(holder);

            setWatchFaceStyle(new WatchFaceStyle.Builder(GirlsWatchFace.this)
                    .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
                    .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
                    .setShowSystemUiTime(false)
                    .build());

            Resources resources = GirlsWatchFace.this.getResources();

            mBackgroundPaint = new Paint();
            mBackgroundPaint.setColor(resources.getColor(R.color.analog_background));

            mTime = new Time();
            
            mBackgroundImg = BitmapFactory.decodeResource(resources, R.drawable.clock_bg);
            mNeedleHour = BitmapFactory.decodeResource(resources, R.drawable.hour);
            mNeedleMin = BitmapFactory.decodeResource(resources, R.drawable.min);
            mNeedleSec = BitmapFactory.decodeResource(resources, R.drawable.second);

            mTextBoxImg = BitmapFactory.decodeResource(resources, R.drawable.fusen);
        }

        @Override
        public void onDestroy() {
            mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
            super.onDestroy();
        }

        @Override
        public void onPropertiesChanged(Bundle properties) {
            super.onPropertiesChanged(properties);
            mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
        }

        @Override
        public void onTimeTick() {
            super.onTimeTick();
            invalidate();
        }

        @Override
        public void onAmbientModeChanged(boolean inAmbientMode) {
            super.onAmbientModeChanged(inAmbientMode);
            if (mAmbient != inAmbientMode) {
                mAmbient = inAmbientMode;
                if (mLowBitAmbient) {
                    mHandPaint.setAntiAlias(!inAmbientMode);
                }
                invalidate();
            }

            // Whether the timer should be running depends on whether we're visible (as well as
            // whether we're in ambient mode), so we may need to start or stop the timer.
            updateTimer();
        }

        void drawClockBackground(Canvas canvas, Rect bounds) {
            canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mBackgroundPaint);
            canvas.drawBitmap(mBackgroundImg, null, bounds, null);
        }

        float mScale = 1f;

        @Override
        public void onDraw(Canvas canvas, Rect bounds) {
            mTime.setToNow();

            int width = bounds.width();
            int height = bounds.height();

            mScale = (float)width / (float)mBackgroundImg.getWidth();

            drawClockBackground(canvas, bounds);

            // Find the center. Ignore the window insets so that, on round watches with a
            // "chin", the watch face is centered on the entire screen, not just the usable
            // portion.
            float centerX = width / 2f;
            float centerY = height / 2f;

            float secRot = mTime.second / 30f * (float) Math.PI;
            int minutes = mTime.minute;
            float minRot = minutes / 30f * (float) Math.PI;
            float hrRot = ((mTime.hour + (minutes / 60f)) / 6f) * (float) Math.PI;

            float secLength = centerX - 20;
            float minLength = centerX - 40;
            float hrLength = centerX - 80;

            if (!mAmbient) {
                drawNeedle_Sec(canvas, centerX, centerY, mTime.second);
            }

            drawNeedle_Min(canvas, centerX, centerY, minutes);
            drawNeedle_Hour(canvas, centerX, centerY, mTime.hour % 12, minutes);
        }

        void drawNeedle_Sec(Canvas canvas, float centerX, float centerY, float seconds) {
            canvas.save();
            canvas.rotate(360f / 60f * seconds + 180f, centerX, centerY);

            float x = centerX - mNeedleSec.getWidth()*mScale/2;
            float y = centerY - 82f*mScale;

            RectF destRect = new RectF(
                    x, y,
                    x + mNeedleSec.getWidth()*mScale,
                    y + mNeedleSec.getHeight()*mScale);

            canvas.drawBitmap(mNeedleSec, null, destRect, null);
            //canvas.drawBitmap(mNeedleSec, centerX - mNeedleSec.getWidth()/2f, centerY-82f, mHandPaint);
            canvas.restore();
        }

        void drawNeedle_Min(Canvas canvas, float centerX, float centerY, float minutes) {
            canvas.save();
            canvas.rotate(360f / 60f * minutes + 180f, centerX, centerY);

            float x = centerX - mNeedleMin.getWidth()*mScale/2;
            float y = centerY - 64f*mScale;

            RectF destRect = new RectF(
                    x, y,
                    x + mNeedleMin.getWidth()*mScale,
                    y + mNeedleMin.getHeight()*mScale);

            canvas.drawBitmap(mNeedleMin, null, destRect, null);
            //canvas.drawBitmap(mNeedleMin, centerX - mNeedleSec.getWidth()/2f, centerY-64f, mHandPaint);
            canvas.restore();
        }

        void drawNeedle_Hour(Canvas canvas, float centerX, float centerY, float hours, float minutes) {
            canvas.save();
            canvas.rotate(360f / 720f * (hours * 60f + minutes) + 180f, centerX, centerY);

            float x = centerX - mNeedleHour.getWidth()*mScale/2;
            float y = centerY - 94f*mScale;

            RectF destRect = new RectF(
                    x, y,
                    x + mNeedleHour.getWidth()*mScale,
                    y + mNeedleHour.getHeight()*mScale);

            canvas.drawBitmap(mNeedleHour, null, destRect, null);
            //canvas.drawBitmap(mNeedleHour, centerX - mNeedleSec.getWidth()/2f, centerY-94f, mHandPaint);
            canvas.restore();
        }

        @Override
        public void onVisibilityChanged(boolean visible) {
            super.onVisibilityChanged(visible);

            if (visible) {
                registerReceiver();

                // Update time zone in case it changed while we weren't visible.
                mTime.clear(TimeZone.getDefault().getID());
                mTime.setToNow();
            } else {
                unregisterReceiver();
            }

            // Whether the timer should be running depends on whether we're visible (as well as
            // whether we're in ambient mode), so we may need to start or stop the timer.
            updateTimer();
        }

        private void registerReceiver() {
            if (mRegisteredTimeZoneReceiver) {
                return;
            }
            mRegisteredTimeZoneReceiver = true;
            IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
            GirlsWatchFace.this.registerReceiver(mTimeZoneReceiver, filter);
        }

        private void unregisterReceiver() {
            if (!mRegisteredTimeZoneReceiver) {
                return;
            }
            mRegisteredTimeZoneReceiver = false;
            GirlsWatchFace.this.unregisterReceiver(mTimeZoneReceiver);
        }

        /**
         * Starts the {@link #mUpdateTimeHandler} timer if it should be running and isn't currently
         * or stops it if it shouldn't be running but currently is.
         */
        private void updateTimer() {
            mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
            if (shouldTimerBeRunning()) {
                mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
            }
        }

        /**
         * Returns whether the {@link #mUpdateTimeHandler} timer should be running. The timer should
         * only run when we're visible and in interactive mode.
         */
        private boolean shouldTimerBeRunning() {
            return isVisible() && !isInAmbientMode();
        }
    }
}
โš ๏ธ **GitHub.com Fallback** โš ๏ธ