├── .gitignore
├── .metadata
├── CHANGELOG.md
├── LICENSE
├── README.md
├── android
├── .gitignore
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── com
│ └── mjohnsullivan
│ └── flutterwear
│ └── wear
│ └── WearPlugin.kt
├── example
├── .gitignore
├── .metadata
├── README.md
├── analysis_options.yaml
├── android
│ ├── .gitignore
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── mjohnsullivan
│ │ │ │ │ └── flutterwear
│ │ │ │ │ └── wear_example
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── res
│ │ │ │ ├── drawable
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ └── values
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── lib
│ └── main.dart
└── pubspec.yaml
├── lib
├── src
│ ├── ambient_widget.dart
│ ├── shape_widget.dart
│ └── wear.dart
└── wear.dart
└── pubspec.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .dart_tool/
3 | .idea/
4 | .pub/
5 | .vscode/
6 | build/
7 | .packages
8 | pubspec.lock
9 | *.iml
10 |
11 | # iOS not required for this plugin
12 | ios/**
13 | windows/**
14 | macos/**
15 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: c4ed4555f4ec04167b0ac024af6f895e9a3c9e76
8 | channel: dev_custom
9 |
10 | project_type: plugin
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 1.1.0
2 |
3 | - Fix issue with non-windows builds breaking.
4 |
5 | # 1.0.0
6 |
7 | - Null Safety Migration (Finally!)
8 | - Thanks to Rexios and Peter Ullrich.
9 | - Min Dart 2.12 / Flutter 2.5
10 | - Updated native component versions:
11 | - Gradle 6.5
12 | - Android Gradle Plugin 4.1.0
13 | - Android compileSdkVersion 31
14 | - AndroidX Wear 1.2.0
15 | - Kotlin 1.5.10
16 | - Removed `jcenter()` repo requirement.
17 |
18 | # 0.1.1
19 |
20 | - Fix Kotlin/Android compileOnly dep on com.google.android.wearable:wearable.
21 |
22 | # 0.1.0
23 |
24 | - Updated to AndroidX and Android embedding v2.
25 | - Renamed `Shape` is now `WearShape`.
26 | - Renamed `Mode` is now `WearMode`.
27 | - Deprecated `InheritedShape`.
28 | _Add `WatchShape` instead and use `WatchShape.of(context)` to get the shape value._
29 |
30 | # 0.0.1
31 |
32 | - Initial release
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2018 The Chromium Authors. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above
10 | copyright notice, this list of conditions and the following
11 | disclaimer in the documentation and/or other materials provided
12 | with the distribution.
13 | * Neither the name of Google Inc. nor the names of its
14 | contributors may be used to endorse or promote products derived
15 | from this software without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter Wear Plugin
2 |
3 | A plugin that offers Flutter support for Wear OS by Google (Android Wear).
4 |
5 | __To use this plugin you must set your `minSdkVersion` to `23`.__
6 |
7 |
8 | # Tutorial
9 |
10 | https://medium.com/flutter-community/flutter-building-wearos-app-fedf0f06d1b4
11 |
12 |
13 | # Widgets
14 |
15 | There currently three widgets provided by the plugin:
16 |
17 | * WatchShape: determines whether the watch is square or round.
18 | * AmbientMode: builder that provides what mode the watch is in. The widget will rebuild whenever the watch changes mode.
19 |
20 |
21 | ## Example
22 |
23 | Typically, all three of these widgets would be used near the root of your app's widget tree:
24 |
25 | ```dart
26 | class WatchScreen extends StatelessWidget {
27 | @override
28 | Widget build(BuildContext context) {
29 | return WatchShape(
30 | builder: (BuildContext context, WearShape shape, Widget? child) {
31 | return AmbientMode(
32 | builder: (context, mode, child) {
33 | return mode == Mode.active ? ActiveWatchFace() : AmbientWatchFace();
34 | },
35 | );
36 | },
37 | );
38 | }
39 | }
40 | ```
41 |
42 | # Old Requirements
43 |
44 | **You DO NOT need to modify these files anymore:**
45 |
46 | You can remove all the old wearable references from the previous release. This plugin
47 | automatically adds all required references and settings.
48 |
49 | 1. `build.gradle`: _wearable dependencies_
50 |
51 | 2. `AndroidManifest.xml`: _`WAKE_LOCK` and `android.hardware.type.watch`
52 | and `com.google.android.wearable.standalone`._
53 |
54 | 3. `MainActivity.kt` or `MainActivity.java`: _all `AmbientMode` references._
55 |
56 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | local.properties
4 | .DS_Store
5 | .idea/
6 | build/
7 | /captures
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | group 'com.mjohnsullivan.flutterwear.wear'
2 | version '1.0-SNAPSHOT'
3 |
4 | buildscript {
5 | ext.kotlin_version = '1.5.10'
6 | repositories {
7 | google()
8 | mavenCentral()
9 | }
10 |
11 | dependencies {
12 | classpath 'com.android.tools.build:gradle:4.1.0'
13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14 | }
15 | }
16 |
17 | rootProject.allprojects {
18 | repositories {
19 | google()
20 | mavenCentral()
21 | }
22 | }
23 |
24 | apply plugin: 'com.android.library'
25 | apply plugin: 'kotlin-android'
26 | //apply plugin: 'kotlin-android-extensions'
27 |
28 | android {
29 | compileSdkVersion 31
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 | defaultConfig {
35 | minSdkVersion 23
36 | }
37 | lintOptions {
38 | disable 'InvalidPackage'
39 | }
40 | }
41 |
42 | dependencies {
43 | //implementation "androidx.core:core-ktx:+"
44 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
45 | implementation 'androidx.wear:wear:1.2.0'
46 | implementation 'com.google.android.support:wearable:2.8.1'
47 | compileOnly 'com.google.android.wearable:wearable:2.8.1'
48 |
49 | // compileOnly files('C:\\Android\\flutter\\bin\\cache\\artifacts\\engine\\android-x64\\flutter.jar')
50 | }
51 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | android.useAndroidX=true
2 | android.enableJetifier=true
3 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
6 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'wear'
2 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/com/mjohnsullivan/flutterwear/wear/WearPlugin.kt:
--------------------------------------------------------------------------------
1 | package com.mjohnsullivan.flutterwear.wear
2 |
3 | import android.os.Bundle
4 | import androidx.core.view.ViewCompat.getRootWindowInsets
5 | import androidx.lifecycle.Lifecycle
6 | import androidx.lifecycle.LifecycleObserver
7 | import androidx.lifecycle.OnLifecycleEvent
8 | import com.google.android.wearable.compat.WearableActivityController
9 | import io.flutter.embedding.engine.plugins.FlutterPlugin
10 | import io.flutter.embedding.engine.plugins.activity.ActivityAware
11 | import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
12 | import io.flutter.embedding.engine.plugins.lifecycle.HiddenLifecycleReference
13 | import io.flutter.plugin.common.MethodCall
14 | import io.flutter.plugin.common.MethodChannel
15 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler
16 | import io.flutter.plugin.common.MethodChannel.Result
17 |
18 |
19 | class WearPlugin : FlutterPlugin, ActivityAware, MethodCallHandler, LifecycleObserver {
20 | private var mAmbientCallback = WearableAmbientCallback()
21 | private var mMethodChannel: MethodChannel? = null
22 | private var mActivityBinding: ActivityPluginBinding? = null
23 | private var mAmbientController: WearableActivityController? = null
24 |
25 | companion object {
26 | const val TAG = "WearPlugin"
27 | const val BURN_IN_PROTECTION = WearableActivityController.EXTRA_BURN_IN_PROTECTION
28 | const val LOW_BIT_AMBIENT = WearableActivityController.EXTRA_LOWBIT_AMBIENT
29 | }
30 |
31 | override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
32 | mMethodChannel = MethodChannel(binding.binaryMessenger, "wear")
33 | mMethodChannel!!.setMethodCallHandler(this)
34 | }
35 |
36 | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
37 | mMethodChannel?.setMethodCallHandler(this)
38 | mMethodChannel = null
39 | }
40 |
41 | override fun onAttachedToActivity(binding: ActivityPluginBinding) {
42 | attachAmbientController(binding)
43 | }
44 |
45 | override fun onDetachedFromActivityForConfigChanges() {
46 | detachAmbientController()
47 | }
48 |
49 | override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
50 | attachAmbientController(binding)
51 | }
52 |
53 | override fun onDetachedFromActivity() {
54 | detachAmbientController()
55 | }
56 |
57 | private fun attachAmbientController(binding: ActivityPluginBinding) {
58 | mActivityBinding = binding
59 | mAmbientController = WearableActivityController(TAG, binding.activity, mAmbientCallback)
60 | mAmbientController?.setAmbientEnabled()
61 | val reference = (binding.lifecycle as HiddenLifecycleReference)
62 | reference.lifecycle.addObserver(this)
63 | }
64 |
65 | private fun detachAmbientController() {
66 | mActivityBinding?.let {
67 | val reference = (it.lifecycle as HiddenLifecycleReference)
68 | reference.lifecycle.removeObserver(this)
69 | }
70 | mActivityBinding = null
71 |
72 | }
73 |
74 | override fun onMethodCall(call: MethodCall, result: Result) {
75 | when (call.method) {
76 | "getShape" -> {
77 | val activity = mActivityBinding?.activity
78 | when {
79 | activity == null -> {
80 | result.error("no-activity", "No android activity available.", null)
81 | }
82 | activity.resources.configuration.isScreenRound -> {
83 | result.success("round")
84 | }
85 | else -> {
86 | result.success("square")
87 | }
88 | }
89 | }
90 | "isAmbient" -> {
91 | result.success(mAmbientController?.isAmbient ?: false)
92 | }
93 | "setAutoResumeEnabled" -> {
94 | val enabled = call.argument("enabled")
95 | if (mAmbientController == null || enabled == null) {
96 | result.error("not-ready", "Ambient mode controller not ready", null)
97 | } else {
98 | mAmbientController!!.setAutoResumeEnabled(enabled)
99 | result.success(null)
100 | }
101 | }
102 | "setAmbientOffloadEnabled" -> {
103 | val enabled = call.argument("enabled")
104 | if (mAmbientController == null || enabled == null) {
105 | result.error("not-ready", "Ambient mode controller not ready", null)
106 | } else {
107 | mAmbientController!!.setAmbientOffloadEnabled(enabled)
108 | result.success(null)
109 | }
110 | }
111 | else -> result.notImplemented()
112 | }
113 | }
114 |
115 | @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
116 | fun onCreate() {
117 | mAmbientController?.onCreate()
118 | }
119 |
120 | @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
121 | fun onResume() {
122 | mAmbientController?.onResume()
123 | }
124 |
125 | @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
126 | fun onPause() {
127 | mAmbientController?.onPause()
128 | }
129 |
130 | @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
131 | fun onStop() {
132 | mAmbientController?.onStop()
133 | }
134 |
135 | @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
136 | fun onDestroy() {
137 | mAmbientController?.onDestroy()
138 | }
139 |
140 | inner class WearableAmbientCallback : WearableActivityController.AmbientCallback() {
141 | override fun onEnterAmbient(ambientDetails: Bundle) {
142 | val burnInProtection = ambientDetails.getBoolean(BURN_IN_PROTECTION, false)
143 | val lowBitAmbient = ambientDetails.getBoolean(LOW_BIT_AMBIENT, false)
144 | mMethodChannel?.invokeMethod("onEnterAmbient", mapOf(
145 | "burnInProtection" to burnInProtection,
146 | "lowBitAmbient" to lowBitAmbient
147 | ))
148 | }
149 |
150 | override fun onExitAmbient() {
151 | mMethodChannel?.invokeMethod("onExitAmbient", null)
152 | }
153 |
154 | override fun onUpdateAmbient() {
155 | mMethodChannel?.invokeMethod("onUpdateAmbient", null)
156 | }
157 |
158 | override fun onInvalidateAmbientOffload() {
159 | mMethodChannel?.invokeMethod("onInvalidateAmbientOffload", null)
160 | }
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # iOS not required for this plugin
44 | ios/**
45 | windows/**
46 | macos/**
47 |
--------------------------------------------------------------------------------
/example/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: c4ed4555f4ec04167b0ac024af6f895e9a3c9e76
8 | channel: dev_custom
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # wear_example
2 |
3 | Demonstrates how to use the wear plugin.
4 |
--------------------------------------------------------------------------------
/example/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /.idea
7 | local.properties
8 | GeneratedPluginRegistrant.java
9 |
10 | # Remember to never publicly share your keystore.
11 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
12 | key.properties
13 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if(localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if(flutterRoot == null) {
11 | throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if(flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if(flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 31
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
41 | applicationId "com.mjohnsullivan.flutterwear.wear_example"
42 | minSdkVersion 23
43 | targetSdkVersion 25
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | }
47 |
48 | buildTypes {
49 | release {
50 | // TODO: Add your own signing config for the release build.
51 | // Signing with the debug keys for now, so `flutter run --release` works.
52 | signingConfig signingConfigs.debug
53 | }
54 | }
55 | }
56 |
57 | flutter {
58 | source '../..'
59 | }
60 |
61 | dependencies {
62 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
63 | }
64 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
9 |
13 |
20 |
24 |
28 |
33 |
37 |
38 |
39 |
40 |
41 |
42 |
44 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/com/mjohnsullivan/flutterwear/wear_example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.mjohnsullivan.flutterwear.wear_example
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fluttercommunity/flutter_wear_plugin/2d087627a6f5c32245a7f19eed999dee6b3c5085/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fluttercommunity/flutter_wear_plugin/2d087627a6f5c32245a7f19eed999dee6b3c5085/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fluttercommunity/flutter_wear_plugin/2d087627a6f5c32245a7f19eed999dee6b3c5085/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fluttercommunity/flutter_wear_plugin/2d087627a6f5c32245a7f19eed999dee6b3c5085/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fluttercommunity/flutter_wear_plugin/2d087627a6f5c32245a7f19eed999dee6b3c5085/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.5.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.1.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | android.useAndroidX=true
2 | android.enableJetifier=true
3 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:wear/wear.dart';
3 |
4 | void main() => runApp(MyApp());
5 |
6 | class MyApp extends StatelessWidget {
7 | @override
8 | Widget build(BuildContext context) {
9 | return MaterialApp(
10 | home: Scaffold(
11 | body: Center(
12 | child: WatchShape(
13 | builder: (BuildContext context, WearShape shape, Widget? child) {
14 | return Column(
15 | mainAxisAlignment: MainAxisAlignment.center,
16 | children: [
17 | Text(
18 | 'Shape: ${shape == WearShape.round ? 'round' : 'square'}',
19 | ),
20 | child!,
21 | ],
22 | );
23 | },
24 | child: AmbientMode(
25 | builder: (BuildContext context, WearMode mode, Widget? child) {
26 | return Text(
27 | 'Mode: ${mode == WearMode.active ? 'Active' : 'Ambient'}',
28 | );
29 | },
30 | ),
31 | ),
32 | ),
33 | ),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: wear_example
2 | description: Demonstrates how to use the wear plugin.
3 | publish_to: 'none'
4 |
5 | environment:
6 | sdk: ">=2.12.0 <3.0.0"
7 | flutter: ">=2.5.0"
8 |
9 | dependencies:
10 | wear:
11 | path: ../
12 | flutter:
13 | sdk: flutter
14 | flutter_lints: ^1.0.4
15 |
16 | dev_dependencies:
17 | flutter_test:
18 | sdk: flutter
19 |
20 | flutter:
21 | uses-material-design: true
22 |
--------------------------------------------------------------------------------
/lib/src/ambient_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:wear/src/wear.dart';
3 |
4 | /// Ambient modes for a Wear device
5 | enum WearMode { active, ambient }
6 |
7 | /// Builds a child for [AmbientMode]
8 | typedef Widget AmbientModeWidgetBuilder(BuildContext context, WearMode mode, Widget? child);
9 |
10 | /// Widget that listens for when a Wear device enters full power or ambient mode,
11 | /// and provides this in a builder. It optionally takes an [onUpdate] function that's
12 | /// called every time the wear device triggers an ambient update request.
13 | @immutable
14 | class AmbientMode extends StatefulWidget {
15 | const AmbientMode({
16 | Key? key,
17 | required this.builder,
18 | this.child,
19 | this.onUpdate,
20 | }) : super(key: key);
21 |
22 | final AmbientModeWidgetBuilder builder;
23 | final Widget? child;
24 |
25 | /// Called each time the the wear device triggers an ambient update request.
26 | final VoidCallback? onUpdate;
27 |
28 | /// Get current [WearMode].
29 | static WearMode wearModeOf(BuildContext context) {
30 | return context.dependOnInheritedWidgetOfExactType<_InheritedAmbientMode>()!.mode;
31 | }
32 |
33 | /// Get current [AmbientDetails].
34 | static AmbientDetails ambientDetailsOf(BuildContext context) {
35 | return context.dependOnInheritedWidgetOfExactType<_InheritedAmbientMode>()!.details;
36 | }
37 |
38 | @override
39 | _AmbientModeState createState() => _AmbientModeState();
40 | }
41 |
42 | class _AmbientModeState extends State with AmbientCallback {
43 | var _ambientMode = WearMode.active;
44 | var _ambientDetails = AmbientDetails(false, false);
45 |
46 | @override
47 | void initState() {
48 | super.initState();
49 | Wear.instance.registerAmbientCallback(this);
50 | Wear.instance.isAmbient().then(_updateMode);
51 | }
52 |
53 | @override
54 | void dispose() {
55 | Wear.instance.unregisterAmbientCallback(this);
56 | super.dispose();
57 | }
58 |
59 | @override
60 | Widget build(BuildContext context) {
61 | return _InheritedAmbientMode(
62 | mode: _ambientMode,
63 | details: _ambientDetails,
64 | child: Builder(
65 | builder: (BuildContext context) {
66 | return widget.builder(context, _ambientMode, widget.child);
67 | },
68 | ),
69 | );
70 | }
71 |
72 | void _updateMode(bool isAmbient) {
73 | if (mounted) {
74 | setState(() => _ambientMode = isAmbient ? WearMode.ambient : WearMode.active);
75 | }
76 | }
77 |
78 | @override
79 | void onEnterAmbient(AmbientDetails ambientDetails) => _updateMode(true);
80 |
81 | @override
82 | void onExitAmbient() => _updateMode(false);
83 |
84 | @override
85 | void onUpdateAmbient() {
86 | _updateMode(true);
87 | widget.onUpdate?.call();
88 | }
89 | }
90 |
91 | class _InheritedAmbientMode extends InheritedWidget {
92 | const _InheritedAmbientMode({
93 | Key? key,
94 | required this.mode,
95 | required this.details,
96 | required Widget child,
97 | }) : super(key: key, child: child);
98 |
99 | final WearMode mode;
100 | final AmbientDetails details;
101 |
102 | @override
103 | bool updateShouldNotify(_InheritedAmbientMode old) {
104 | return mode != old.mode || details != old.details;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/lib/src/shape_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 | import 'package:wear/src/wear.dart';
3 |
4 | /// Shape of a Wear device
5 | enum WearShape { square, round }
6 |
7 | /// Builds a child for a [WatchShape]
8 | typedef Widget WatchShapeBuilder(BuildContext context, WearShape shape, Widget? child);
9 |
10 | /// Builder widget for watch shapes
11 | @immutable
12 | class WatchShape extends StatefulWidget {
13 | const WatchShape({
14 | Key? key,
15 | required this.builder,
16 | this.child,
17 | }) : super(key: key);
18 |
19 | final WatchShapeBuilder builder;
20 | final Widget? child;
21 |
22 | /// Call [WatchShape.of(context)] to retrieve the shape further down
23 | /// in the widget hierarchy.
24 | static WearShape of(BuildContext context) {
25 | // ignore: deprecated_member_use_from_same_package
26 | return InheritedShape.of(context).shape;
27 | }
28 |
29 | @override
30 | _WatchShapeState createState() => _WatchShapeState();
31 | }
32 |
33 | class _WatchShapeState extends State {
34 | late WearShape _shape;
35 |
36 | @override
37 | void initState() {
38 | super.initState();
39 | // Default to round until the platform returns the shape
40 | // round being the most common form factor for WearOS
41 | _shape = WearShape.round;
42 | Wear.instance.getShape().then((String shape) {
43 | if (mounted) {
44 | setState(() => _shape = (shape == 'round' ? WearShape.round : WearShape.square));
45 | }
46 | });
47 | }
48 |
49 | @override
50 | Widget build(BuildContext context) {
51 | // ignore: deprecated_member_use_from_same_package
52 | return InheritedShape(
53 | shape: _shape,
54 | child: Builder(
55 | builder: (BuildContext context) {
56 | return widget.builder(context, _shape, widget.child);
57 | },
58 | ),
59 | );
60 | }
61 | }
62 |
63 | /// An inherited widget that holds the shape of the Watch
64 | @Deprecated("Add WatchShape instead and use WatchShape.of(context) to get the shape value.")
65 | class InheritedShape extends InheritedWidget {
66 | const InheritedShape({
67 | Key? key,
68 | required this.shape,
69 | required Widget child,
70 | }) : super(key: key, child: child);
71 |
72 | final WearShape shape;
73 |
74 | static InheritedShape of(BuildContext context) {
75 | return context.dependOnInheritedWidgetOfExactType()!;
76 | }
77 |
78 | @override
79 | bool updateShouldNotify(InheritedShape old) => shape != old.shape;
80 | }
81 |
--------------------------------------------------------------------------------
/lib/src/wear.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart' show debugPrint;
2 | import 'package:flutter/services.dart' show MethodChannel, MethodCall, PlatformException;
3 |
4 | class Wear {
5 | static const MethodChannel _channel = MethodChannel('wear');
6 |
7 | factory Wear() => instance;
8 |
9 | static final instance = Wear._();
10 |
11 | Wear._() {
12 | _channel.setMethodCallHandler(_onMethodCallHandler);
13 | }
14 |
15 | final _ambientCallbacks = [];
16 |
17 | /// Register callback for ambient notifications
18 | void registerAmbientCallback(AmbientCallback callback) {
19 | _ambientCallbacks.add(callback);
20 | }
21 |
22 | /// Unregister callback for ambient notifications
23 | void unregisterAmbientCallback(AmbientCallback callback) {
24 | _ambientCallbacks.remove(callback);
25 | }
26 |
27 | Future _onMethodCallHandler(MethodCall call) async {
28 | switch (call.method) {
29 | case 'onEnterAmbient':
30 | final args = (call.arguments as Map).cast();
31 | final details = AmbientDetails(args['burnInProtection']!, args['lowBitAmbient']!);
32 | _notifyAmbientCallbacks((callback) => callback.onEnterAmbient(details));
33 | break;
34 | case 'onExitAmbient':
35 | _notifyAmbientCallbacks((callback) => callback.onExitAmbient());
36 | break;
37 | case 'onUpdateAmbient':
38 | _notifyAmbientCallbacks((callback) => callback.onUpdateAmbient());
39 | break;
40 | case 'onInvalidateAmbientOffload':
41 | _notifyAmbientCallbacks((callback) => callback.onInvalidateAmbientOffload());
42 | break;
43 | }
44 | }
45 |
46 | void _notifyAmbientCallbacks(Function(AmbientCallback callback) fn) {
47 | final callbacks = List.from(_ambientCallbacks);
48 | for (final callback in callbacks) {
49 | try {
50 | fn(callback);
51 | } catch (e, st) {
52 | debugPrint('Failed callback: $callback\n$e\n$st');
53 | }
54 | }
55 | }
56 |
57 | /// Fetches the shape of the watch face
58 | Future getShape() async {
59 | try {
60 | return (await _channel.invokeMethod('getShape'))!;
61 | } on PlatformException catch (e, st) {
62 | // Default to round
63 | debugPrint('Error calling getShape: $e\n$st');
64 | return 'round';
65 | }
66 | }
67 |
68 | /// Tells the application if we are currently in ambient mode
69 | Future isAmbient() async {
70 | try {
71 | return (await _channel.invokeMethod('isAmbient'))!;
72 | } on PlatformException catch (e, st) {
73 | debugPrint('Error calling isAmbient: $e\n$st');
74 | return false;
75 | }
76 | }
77 |
78 | /// Sets whether this activity's task should be moved to the front when
79 | /// the system exits ambient mode.
80 | ///
81 | /// If true, the activity's task may be moved to the front if it was the
82 | /// last activity to be running when ambient started, depending on how
83 | /// much time the system spent in ambient mode.
84 | ///
85 | Future setAutoResumeEnabled(bool enabled) async {
86 | try {
87 | await _channel.invokeMethod(
88 | 'setAutoResumeEnabled',
89 | {'enabled': enabled},
90 | );
91 | } on PlatformException catch (e, st) {
92 | debugPrint('Error calling setAutoResumeEnabled: $e\n$st');
93 | rethrow;
94 | }
95 | }
96 |
97 | /// Sets whether this activity is currently in a state that supports ambient offload mode.
98 | Future setAmbientOffloadEnabled(bool enabled) async {
99 | try {
100 | await _channel.invokeMethod(
101 | 'setAmbientOffloadEnabled',
102 | {'enabled': enabled},
103 | );
104 | } on PlatformException catch (e, st) {
105 | debugPrint('Error calling setAmbientOffloadEnabled: $e\n$st');
106 | rethrow;
107 | }
108 | }
109 | }
110 |
111 | /// Provides details of current ambient mode configuration.
112 | class AmbientDetails {
113 | const AmbientDetails(this.burnInProtection, this.lowBitAmbient);
114 |
115 | /// Used to indicate whether burn-in protection is required.
116 | ///
117 | /// When this property is set to true, views must be shifted around
118 | /// periodically in ambient mode. To ensure that content isn't
119 | /// shifted off the screen, avoid placing content within 10 pixels
120 | /// of the edge of the screen. Activities should also avoid solid
121 | /// white areas to prevent pixel burn-in. Both of these
122 | /// requirements only apply in ambient mode, and only when
123 | /// this property is set to true.
124 | final bool burnInProtection;
125 |
126 | /// Used to indicate whether the device has low-bit ambient mode.
127 | ///
128 | /// When this property is set to true, the screen supports fewer bits
129 | /// for each color in ambient mode. In this case, activities should
130 | /// disable anti-aliasing in ambient mode.
131 | final bool lowBitAmbient;
132 | }
133 |
134 | /// Callback to receive ambient mode state changes.
135 | abstract class AmbientCallback {
136 | /// Called when an activity is entering ambient mode.
137 | void onEnterAmbient(AmbientDetails ambientDetails) {}
138 |
139 | /// Called when an activity should exit ambient mode.
140 | void onExitAmbient() {}
141 |
142 | /// Called when the system is updating the display for ambient mode.
143 | void onUpdateAmbient() {}
144 |
145 | /// Called to inform an activity that whatever decomposition it has sent to
146 | /// Sidekick is no longer valid and should be re-sent before enabling ambient offload.
147 | void onInvalidateAmbientOffload() {}
148 | }
149 |
--------------------------------------------------------------------------------
/lib/wear.dart:
--------------------------------------------------------------------------------
1 | library wear;
2 |
3 | export 'src/ambient_widget.dart';
4 | export 'src/shape_widget.dart';
5 | export 'src/wear.dart';
6 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: wear
2 | description: A plugin that offers Flutter support for Wear OS by Google
3 | version: 1.1.0
4 | homepage: https://github.com/fluttercommunity/flutter_wear_plugin
5 |
6 | environment:
7 | sdk: ">=2.12.0 <3.0.0"
8 | flutter: ">=2.5.0"
9 |
10 | dependencies:
11 | flutter:
12 | sdk: flutter
13 |
14 | flutter:
15 | plugin:
16 | platforms:
17 | android:
18 | package: com.mjohnsullivan.flutterwear.wear
19 | pluginClass: WearPlugin
20 |
--------------------------------------------------------------------------------