user4360138
user4360138

Reputation: 23

How to deploy and run watch face service

I am following this tutorial on how to make a custom watch face. After copying code and setting up the project properly (besides making coordinates dynamic for each and every watch) , I don't know how to actually run the app. I will post the project and code here:

And the code:

public class ZCycleWatchFaceService extends CanvasWatchFaceService{//Made specifically for moto 360

    @Override
    public Engine onCreateEngine() {
        /* provide your watch face implementation */
        return new Engine();
    }

    /* implement service callback methods */
    private class Engine extends CanvasWatchFaceService.Engine {

        static final int MSG_UPDATE_TIME = 0;
        static final int INTERACTIVE_UPDATE_RATE_MS = 1000;

        RectF smallCircleRect;
        RectF bigCircleRect;

        /* a time object */
        Time mTime;

        /* device features */
        boolean mLowBitAmbient;
        boolean mBurnInProtection;

        float textY = 135;
        float textSize = 20;

        /* graphic objects */
        Paint mHourPaint;
        Paint mMinutePaint;
        Paint mTextPaint;

        /* 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;
                }
            }
        };

        /* receiver to update the time zone */
        final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                mTime.clear(intent.getStringExtra("time-zone"));
                mTime.setToNow();
            }
        };

        private void updateTimer() {
            mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
            if (shouldTimerBeRunning()) {
                mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
            }
        }

        private boolean shouldTimerBeRunning() {
            return isVisible() && !isInAmbientMode();
        }

        @Override
        public void onCreate(SurfaceHolder holder) {
            super.onCreate(holder);
            /* initialize your watch face */

            bigCircleRect = new RectF(5 , 5 , 315 , 280);
            smallCircleRect = new RectF(15 , 15 , 305 , 270);

            /* create graphic styles */
            mHourPaint = new Paint();
            mHourPaint.setARGB(255, 77 , 175 , 240);
            mHourPaint.setStrokeWidth(5.0f);
            mHourPaint.setAntiAlias(true);
            mHourPaint.setStrokeCap(Paint.Cap.ROUND);
            mHourPaint.setTextSize(textSize);

            mMinutePaint = new Paint();
            mMinutePaint.setARGB(225 , 240 , 150 , 77);
            mMinutePaint.setStrokeWidth(3.5f);
            mMinutePaint.setAntiAlias(true);
            mMinutePaint.setStrokeCap(Paint.Cap.ROUND);


            /* allocate an object to hold the time */
            mTime = new Time();

            /* configure the system UI */
            setWatchFaceStyle(new WatchFaceStyle.Builder(ZCycleWatchFaceService.this)
                    .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
                    .setBackgroundVisibility(WatchFaceStyle
                            .BACKGROUND_VISIBILITY_INTERRUPTIVE)
                    .setShowSystemUiTime(false)
                    .build());

        }

        @Override
        public void onPropertiesChanged(Bundle properties) {
            /* get device features (burn-in, low-bit ambient) */
            super.onPropertiesChanged(properties);
            mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
            mBurnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION,
                    false);
        }

        @Override
        public void onTimeTick() {
            /* the time changed */
            super.onTimeTick();

            invalidate();
        }

        @Override
        public void onAmbientModeChanged(boolean inAmbientMode) {
            /* the wearable switched between modes */
            boolean wasInAmbientMode = isInAmbientMode();
            super.onAmbientModeChanged(inAmbientMode);

            if (inAmbientMode != wasInAmbientMode) {
                if (mLowBitAmbient) {
                    boolean antiAlias = !inAmbientMode;
                    mHourPaint.setAntiAlias(antiAlias);
                    mMinutePaint.setAntiAlias(antiAlias);

                    //mSecondPaint.setAntiAlias(antiAlias);
                    //mTickPaint.setAntiAlias(antiAlias);
                }
                invalidate();
                updateTimer();
            }
        }

        @Override
        public void onDraw(Canvas canvas, Rect bounds) {
            /* draw your watch face */
            // Update the time
            mTime.setToNow();

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

            // 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 circleCenter = centerY + FLAT_TIRE_OFFSET;

            float minsPassed = mTime.minute;
            float hoursPassed = mTime.hour;
            float secsPassed = mTime.second;

            float timePassedForBigCircle = minsPassed + hoursPassed * 60;
            double radsForBigCircle = 0.87222222292 * timePassedForBigCircle;
            double radsForSmallCircle = 10.4666667 * minsPassed;

            double degForBigCircle = Math.toDegrees(radsForBigCircle);
            double degForSmallCircle = Math.toDegrees(radsForSmallCircle);

            canvas.drawArc(bigCircleRect , 0 , (float) degForBigCircle , false , mHourPaint);
            canvas.drawArc(smallCircleRect , 0 , (float) degForSmallCircle , false , mMinutePaint);

            float textX = 0;

            if(hoursPassed >= 10){
                textX = 320 - textSize * 4;
            }else{
                textX = textSize * 5;
            }

            canvas.drawText(hoursPassed + ":" + minsPassed , textX , textY , mHourPaint);
            /*// Compute rotations and lengths for the clock hands.
            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;

            // Only draw the second hand in interactive mode.
            /*if (!mAmbient) {
                float secX = (float) Math.sin(secRot) * secLength;
                float secY = (float) -Math.cos(secRot) * secLength;
                canvas.drawLine(centerX, centerY, centerX + secX, centerY +
                        secY, mSecondPaint);
            }*/

            /*// Draw the minute and hour hands.
            float minX = (float) Math.sin(minRot) * minLength;
            float minY = (float) -Math.cos(minRot) * minLength;
            canvas.drawLine(centerX, centerY, centerX + minX, centerY + minY,
                    mMinutePaint);
            float hrX = (float) Math.sin(hrRot) * hrLength;
            float hrY = (float) -Math.cos(hrRot) * hrLength;
            canvas.drawLine(centerX, centerY, centerX + hrX, centerY + hrY,
                    mHourPaint);*/
        }

        @Override
        public void onVisibilityChanged(boolean visible) {
            /* the watch face became visible or invisible */
            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 and
            // 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);
            ZCycleWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter);
        }

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

    }

}

Most of it doesn't do much yet, I just want to test my drawing mechanics

Manifest files: Manifest file for wear:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.rfsdev.zarkopafilis.zcycle">
    <uses-feature android:name="android.hardware.type.watch" />
    <application android:allowBackup="true" android:label="@string/app_name"
        android:icon="@drawable/ic_launcher" android:theme="@android:style/Theme.DeviceDefault">

    </application>

    <uses-permission
        android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
    <uses-permission
        android:name="android.permission.WAKE_LOCK" />

</manifest>

Manifest file for mobile/phone:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.rfsdev.zarkopafilis.zcycle">

    <application android:allowBackup="true" android:label="@string/app_name"
        android:icon="@drawable/ic_launcher" android:theme="@style/AppTheme">


        <service
            android:name=".ZCycleWatchFaceService"
            android:label="@string/analog_name"
            android:allowEmbedded="true"
            android:taskAffinity=""
            android:permission="android.permission.BIND_WALLPAPER" >
            <intent-filter>
                <action android:name="android.service.wallpaper.WallpaperService" />
                <category
                    android:name=
                        "com.google.android.wearable.watchface.category.WATCH_FACE" />
            </intent-filter>
        </service>


    </application>

    <uses-permission
        android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
    <uses-permission
        android:name="android.permission.WAKE_LOCK" />



</manifest>

I don't know how to test run this thing. The message says 'No activity found' , but im following the tutorial properly. I have already made android applications and this made me confused.

(I do not want tips and stuff for my drawing code , I just want to know what do I need to do in order to run this)

Edit : I don't want to start the application from 'Start...'

Upvotes: 1

Views: 1938

Answers (3)

th3hamm0r
th3hamm0r

Reputation: 676

  1. You do not need the mobile/app module for now, if you only want to deploy and test your watch face. Just select and run your "wear" configuration on the wear device or emulator and assure that "Do not launch Activity" is selected in its settings.
  2. For me it was important to define a preview image, otherwise the watch face will not show up in the selector.
  3. It seems like you've scrambled your manifest files.

Your wear's manifest file should look like this:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="net.rfsdev.zarkopafilis.zcycle">

    <uses-feature android:name="android.hardware.type.watch"/>

    <uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

    <application android:allowBackup="true"
                 android:label="@string/app_name"
                 android:icon="@drawable/ic_launcher"
                 android:theme="@android:style/Theme.DeviceDefault">

        <service
                android:name=".ZCycleWatchFaceService"
                android:label="@string/analog_name"
                android:allowEmbedded="true"
                android:taskAffinity=""
                android:permission="android.permission.BIND_WALLPAPER">
            <meta-data
                    android:name="android.service.wallpaper"
                    android:resource="@xml/watch_face"/>
            <meta-data
                android:name="com.google.android.wearable.watchface.preview"
                android:resource="@drawable/preview" />
            <intent-filter>
                <action android:name="android.service.wallpaper.WallpaperService"/>
                <category android:name="com.google.android.wearable.watchface.category.WATCH_FACE"/>
            </intent-filter>
        </service>

    </application>

</manifest>

Your app's manifest file may look like this:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="net.rfsdev.zarkopafilis.zcycle">

    <uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

    <application android:allowBackup="true"
                 android:label="@string/app_name"
                 android:icon="@mipmap/ic_launcher"
                 android:theme="@style/AppTheme">

    </application>

</manifest>

Upvotes: 0

thakis
thakis

Reputation: 5889

  1. The needs to be in the wear manifest, not in the phone manifest
  2. The must have an

    <meta-data
        android:name="com.google.android.wearable.watchface.preview"
        android:resource="@drawable/preview_my_clock" />
    

    entry, else the watch face won't be shown on the watch face selector.

Once you have made these two changes, long-press on the home screen after uploading your app, and it should show up in the watch face selector.

Upvotes: 0

Mateusz Pryczkowski
Mateusz Pryczkowski

Reputation: 1894

Please remember, that you are not making Android application with Activity, that you can start, but making Android application just with Service. In your case - you should just use option - deploy apk, without starting any Activityenter image description here

Upvotes: 4

Related Questions