Slide 1

Slide 1 text

Android BikeΛ࡞Ζ͏ @tnj

Slide 2

Slide 2 text

@tnj • 2010೥͔ΒAndroidΤϯδχΞ • mixiͷެࣜΫϥΠΞϯτΞϓϦ্ཱͪ͛ • DeployGateͱ͍͏ձࣾΛ΍ͬͯ·͢

Slide 3

Slide 3 text

ࠓ೔ͷ࿩ʢ໿30෼ʣ

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

͜ΜͳΞϓϦ࡞ͬͯͨ • αΠίϯΞϓϦɺࣗసंͷϝʔλʔ • खܰʹ࢖͑ͯɺͦΕͳΓʹݟͨ໨ָ͕ͯ͘͠ɺ ࣮༻తͳ΍ͭ • ͦΕͳΓʹಈ͚͘ͲɺϓϩτλΠϓ • ͜ΕΛ࡞ΔதͰɺ͍ΖΜͳ஌ݟͱ᠘Λಘͨ • ஌ࣝ΍ମݧΛڞ༗͍ͨ͠

Slide 6

Slide 6 text

ର৅ • ͬ͘͟ΓAndroid։ൃʹ৮ΕͯΔ͚Ͳ • Bluetoothͱ͔ηϯαͱ͔࢖ͬͨΞϓϦ͸
 ࡞ͬͨ͜ͱ͕ͳ͍ • IoTಐఃͷਓ

Slide 7

Slide 7 text

ʹ1ϲ݄લͷࣗ෼ ʮηϯα΍σόΠεͰԿ͔Ͱ͖Δͱָͦ͠͏ʯ ͱࢥͬͯΔ͚Ͳɺ·ͩ৮ͬͨ͜ͱ͕ͳ͍ ͜ͷηογϣϯͷऴΘΓࠒʹ͸ • ͳΜ͔࡞Γ͍ͨͳͬͯؾ෼ʹͳͬͯ΋Β͑Δ • ͍ΖΜͳΞϓϦΛ࡞Δ͖͔͚ͬʹͳΔͱ͍͍ͳ

Slide 8

Slide 8 text

ΞδΣϯμ • ͖͔͚ͬ • εϚϗͷؾѹηϯαͰߴ౓ܭΛ࡞Δ • BLEͷηϯαͰεϐʔυ/έΠσϯεΛಘΔ • αΠίϯʹಛԽͨ͠ը໘Λ࡞Δ • Θ͔ͬͨ͜ͱ • ·ͱΊͱࠓޙ

Slide 9

Slide 9 text

εϥΠυɺίʔυɺΞϓϦ
 ্͕ͬͯ·͢ URL ͸ Twitter: @tnj Ͱ

Slide 10

Slide 10 text

͖͔͚ͬ

Slide 11

Slide 11 text

ࡢ೥11݄ʹࣗసंങͬͨ GIANT TCR Advanced 2 (2016)

Slide 12

Slide 12 text

ళһ ʮͦ͏͍͑͹αΠίϯͱ͔͚ͭ·͢ʁʯ

Slide 13

Slide 13 text

ࣗ෼ ʮ͋ɺཉ͍͠Ͱ͢ʯ

Slide 14

Slide 14 text

ళһ ʮ͜ͷ্Ґػछͩͱඪ४૷උͷ΍ͭɺ ͚ͭͱ͘ͱεϚϗͱ͔Ͱ
 ݟΕͨΓ͠·͢Αʙʯ

Slide 15

Slide 15 text

Θ͔ͬͨ͜ͱ

Slide 16

Slide 16 text

21ੈلͷࣗసं͸
 BluetoothΛ஻Δ

Slide 17

Slide 17 text

ࣗసं͕BluetoothΛ஻Δ • ंମ͕࠷ॳ͔ΒηϯαReady • ্Ґػछͩͱඪ४૷උͱ͔ • ANT+͕ྲྀߦ͚ͬͯͨͲ
 ࠷ۙ͸Bluetooth Low EnergyԽ͕ਐΜͰΔ

Slide 18

Slide 18 text

͍ΖΜͳΞϓϦΛࢼͨ͠

Slide 19

Slide 19 text

…͚Ͳɺͬ͘͠Γ͜ͳ͍ • ͳΜ͔ݟͨ໨͕޷͖͡Όͳ͔ͬͨΓ
 ૢ࡞͕ҟৗʹ೉͔ͬͨ͠Γ • ηϯαରԠ͕έΠσϯε͚ͩͩͬͨΓ • ඪߴ/ࣼ౓ͷද͕ࣔ·ͬͨ͘ΞςʹͳΒͳ͍

Slide 20

Slide 20 text

ͳ͍ͳΒɺ࡞Δ͔͠ͳ͍

Slide 21

Slide 21 text

Ͳ͏΍ͬͯ • ஋͸Bluetooth LEηϯαͰऔͬͨ΋ͷΛग़͢ • ؾѹηϯα࢖͑͹ߴ౓औΕΔͰ͠ΐ • දࣔ΋ಛԽͨ͠ܗͰ޷͖উख࡞Ζ͏

Slide 22

Slide 22 text

ͱʹ͔͘ϓϩτλΠϓ ࣗ෼ͷ࣋ͬͯΔ୺຤(Nexus 6P)Ͱ • BLEͷσόΠεݕࡧɺ؅ཧͱ஋ͷऔಘ • ηϯαͷ؅ཧͱ஋ͷऔಘ • Ґஔ৘ใͷऔಘ ͯ͠දࣔ͢Δͧ

Slide 23

Slide 23 text

ͬͦ͘͞Bluetooth LE࢖͏ͧ

Slide 24

Slide 24 text

…ͷ·͑ʹ

Slide 25

Slide 25 text

୺຤ͷηϯαΛ࢖ͬͯΈΑ͏ • ᠘͕গͳͦ͏… • ৺͕ંΕʹͦ͘͏… • ੒ޭମݧେࣄ

Slide 26

Slide 26 text

Bosch BMP280 5Ҏ߱ͷNexusγϦʔζ͸ؾѹηϯα౥ࡌ

Slide 27

Slide 27 text

ؾѹܭΞϓϦΛࢼͯ͠ΈΔ চ͔Β಄্΁ͷҠಈ(໿2m)Ͱ΋༗ҙʹมԽ

Slide 28

Slide 28 text

ͱΓ࣮͋͑ͣػͰऔͬͯΈΑ͏ ΍Δ͜ͱ͸ׂͱγϯϓϧ 1. SensorManager Ͱ
 TYPE_PRESSURE ͳηϯαΛ΋Βͬͯ͘Δ 2. SensorEventListener Λ࣮૷͢Δ 3. ϦεφΛ SensorManager ʹొ࿥͢Δ

Slide 29

Slide 29 text

1. SensorManagerͰ
 TYPE_PRESSURE ͳηϯαΛ
 ΋Βͬͯ͘Δ sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); pressure = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);

Slide 30

Slide 30 text

2. SensorEventListener Λ
 ࣮૷͢Δ @Override public void onSensorChanged(SensorEvent event) { if (event.sensor == pressure) { // event.values[0] ʹ float Ͱؾѹ஋͕ೖ͍ͬͯΔ Log.v(TAG, "Pressure: " + event.values[0]); } }

Slide 31

Slide 31 text

3. ϦεφΛొ࿥͢Δ sensorManager.registerListener( this, pressure, SensorManager.SENSOR_DELAY_NORMAL );

Slide 32

Slide 32 text

࣮ߦ! • ݁ߏͳ੎͍Ͱ onSensorChanged ͕ݺ͹Εͯ ஋͕औΕΔ

Slide 33

Slide 33 text

ؾѹ͔Βߴ౓ΛٻΊΔ • ۙࣅࣜʢΧγΦܭࢉػʮߴਫ਼౓ܭࢉαΠτʯΑΓʣ • ݫີʹ͸ւ໘ؾѹͱؾԹ͕ඞཁ • BMP280಺ͷؾԹηϯαͰऔΕΔ͔ͳʁʁ

Slide 34

Slide 34 text

ؾԹηϯα΋ಉ͡Α͏ʹ… • ͱࢥ͚ͬͨͲݟ͔ͭΒͳ͍ • BMP280ʹ͸Թ౓ηϯα΋ࡌͬͯΔ͸ͣʁʁʁ • TYPE_AMBIENT_TEMPERATURE Ͱ͸
 ͳʹ΋औΕͳ͍ • TYPE_TEMPERATURE (deprecated) Ͱ΋
 औΕͳ͍

Slide 35

Slide 35 text

શ෦ྻڍͯ͠୳ͯ͠Έͨ sensor.getName(); // => BMP280 temperature sensor.getStringType(); // => com.google.sensor.internal_temperature sensor.getType(); // => Type=65536 • TYPE_INTERNAL_TEMPERATURE(API 24+) ͩͱ 65537 ❓

Slide 36

Slide 36 text

ద౰ʹϏϡʔʹηοτͨ͠Γ

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

ͳΜ͔ͦΕͳΓʹಈ͍ͯΔ • ͔͠͠஋͕ඈΜͩΓ͢Δ • ͍͖ͳΓ5mͱ͔ඈͿ͜ͱ͕͋Δ • ͖ͭΊʹLow Pass FilterΛֻ͚Δ • ؆қ࣮૷ lastPressure = lastPressure * 0.95f + currentPressure * 0.05f;

Slide 39

Slide 39 text

ͦΜͳʹ༳Εͳ͘ͳΔ

Slide 40

Slide 40 text

ؾԹߴ͗͢໰୊ • ຊମ಺ͷԹ౓ʹͳͬͪΌ͏͔ΒͶ… • ΋͏গ͠ௐ΂ͯΈͨ • ؾԹɾւ໘ؾѹͳ͠Ͱ΋ͦΕͳΓͷਫ਼౓ • ͦ΋ͦ΋ͦ͏͍͏ϝιου͕ SensorManagerʹ༻ҙ͞Εͯͨ SensorManager.getAltitude(pressure, basePressure);

Slide 41

Slide 41 text

஌ݟJavadocʹ ߴ͞ͷࠩΛٻΊΔͱ͖ʹ͸ɺͦΕͧΕͷ஍఺Ͱࢉ ग़ͨ͠ߴ͞ಉ࢜ΛҾ͘΂͠ɻւ໘ؾѹ͕෼͔Βͳ ͚Ε͹ɺPRESSURE_STANDARD_ATMOSPHEREఆ ਺Λ࢖͏ͱҰൠతͳؾѹͳΒ͍͍ͩͨྑ͍݁Ռ͕ ಘΒΕΔɻ To calculate altitude differences, you must calculate the difference between the altitudes at both points. If you don't know the altitude as sea level, you can use {@link #PRESSURE_STANDARD_ATMOSPHERE} instead, which will give good results considering the range of pressure typically involved.

Slide 42

Slide 42 text

ຬΛ࣋ͯ͠Bluetooth LE΁

Slide 43

Slide 43 text

GIANT NEW RIDESENSE (ANT+/BLE) ϗΠʔϧͱΫϥϯΫʹ࣓ੴ͕͋ͬͯɺͦΕ͕ηϯαʹۙ઀ ͢Δ௨Δճ਺Λ਺͑Δ࢓૊Έ

Slide 44

Slide 44 text

Bluetooth Low Energy (Bluetooth 4.0) • Ϙλϯి஑1ݸͰ਺ϲ݄ಈ͔ͤΔ͙Β͍௿ফඅ ిྗʹৼͬͨن֨ • ௨৴ස౓ɺ௨৴ྔ͕࠷௿ݶʢ௨৴ػثͷి ஑ফඅͷཁʣ • ࢖͏νϟϯωϧݮͬͨΓɺϓϩτίϧ͸Ҏ લͱޓ׵ੑͳ͍

Slide 45

Slide 45 text

ΫϥΠΞϯταʔόϞσϧ • ࠓճͩͱ • ࣗసं(ϖϦϑΣϥϧ)͕αʔό • Nexus 6P(ηϯτϥϧ)͕ΫϥΠΞϯτ • ϖϦϑΣϥϧ͕ʮԶͩʔͬʂʯͬͯΞυόλ ΠδϯάΛਨΕྲྀͯ͠ΔͷΛɺηϯτϥϧ͕ εΩϟϯͯ͠ݟ͚ͭΔ

Slide 46

Slide 46 text

AndroidͱBLE • Android 4.3Ҏ্Ͱ࢖͑Δ • Ͱ΋5Ͱ΋6Ͱ΋ͦΕͧΕڍಈ͕ҧ͍ͬͯΔ • άάͬͯΔͱઌۦऀͷࢡΛ௒͍͑ͯ͘ײ͕͍͢͝ • ͓खܰʹ͍ͨ͠ͷͰࠓճ͸7͔͠ݟ·ͤΜʂʂ

Slide 47

Slide 47 text

Ͱɺ • σʔλͬͯͲ͏औಘ͢Δͷʁܗࣜ͸ʁ • BLEʹ͸GATT͍ͬͯ͏ඪ४࢓༷͕͋Γ·͢

Slide 48

Slide 48 text

GATT • Generic ATTribute Profile • ͳʹ͜ͷॳݟࡴ͠ײ͋;ΕΔলུه๏

Slide 49

Slide 49 text

https://www.bluetooth.com/ja-jp/specifications/generic-attributes-overview

Slide 50

Slide 50 text

GATT.Service.Characteristic • GATT • has_many Services
 (ࣗసंαʔϏεɺόοςϦʔαʔϏεͱ͔) • has_many Characteristics
 (ճస਺΍ɺൃੜ࣌ࠁͳͲ࣮ࡍͷ஋) • Service, Characteristic͸ͦΕͧΕܾ·ͬͨUUID ׂ͕Γ౰ͯΒΕ͓ͯΓUUIDͰݕࡧͰ͖Δ

Slide 51

Slide 51 text

ࠓճ࢖͏Service: CSC • Cycling Speed and Cadence Service • ʮBLEରԠʯͬͯࣗసंεϐʔυ/έΠσϯε ηϯα͸͜ΕΛ࣮૷ͯ͠੡඼Խͯ͠Δ

Slide 52

Slide 52 text

…ͷதͷCharacteristic CSC Measurement Characteristic • ϗΠʔϧͱΫϥϯΫͦΕͧΕͷ • ճస਺ • ࠷ޙʹΠϕϯτ͕ൃੜͨ࣌ؒ͠ • ී௨͸1ඵִؒͰૹ৴͞ΕΔ • ΫϥϯΫͷ஋ͰέΠσϯε͕෼͔Δ • ϗΠʔϧճస਺ʹλΠϠܘΛֻ͚ͯ΍Ε͹଎౓͕෼͔Δ

Slide 53

Slide 53 text

19ϖʔδͷ࢓༷ॻPDF

Slide 54

Slide 54 text

Specશ෦ಡΜͰ
 ΍ͬͯ΋͍͍͚Ͳ… ͭΒͦ͏

Slide 55

Slide 55 text

ٹੈओ nRF Toolbox for BLE

Slide 56

Slide 56 text

nRF Toolbox for BLE • Nordic Semiconductor • ௒௿ফඅిྗͷۙڑ཭ແઢʹڧ͍௨৴Ϟ δϡʔϧͷձࣾ • ֤छϓϩϑΝΠϧͷσϞΞϓϦ • Φʔϓϯιʔε (TV΋Wear΋ରԠ) • New BSDϥΠηϯε

Slide 57

Slide 57 text

ಡΈͳ͕Βཧղ ࢖͍ճ͢ʹ͸ن໛͕େ͖͍ͷͰ࣮૷͸ࣗલ

Slide 58

Slide 58 text

͕ʔͬͱ࣮૷ • ·ͣҐஔ৘ใͷPermissionऔಘ͕ඞཁ (Android 6.0Ҏ߱) • Runtime Permission΍ʂ

Slide 59

Slide 59 text

by @hotchemi

Slide 60

Slide 60 text

1. Activityʹ @RuntimePermissions ͚ͬͯͭͯ @RuntimePermissions public class MainActivity {

Slide 61

Slide 61 text

2. onRequestPermissionsResult Λதܧͯ͠४උ׬ྃ @Override public void onRequestPermissionsResult( int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { MainActivityPermissionsDispatcher .onRequestPermissionsResult(this, requestCode, grantResults); };

Slide 62

Slide 62 text

3. ύʔϛογϣϯ͕ඞཁͳ
 ؔ਺ʹΞϊςʔγϣϯॻ͍ͯ @NeedsPermission(Manifest.permission.ACCESS_FINE_LOCATION) void startBleScan() {

Slide 63

Slide 63 text

4. ؔ਺ݺͼग़͠Λ
 ஔ͖׵͑ͯ΍Δ // startBleScan(); ΛҎԼʹஔ͖׵͑ MainActivityPermissionsDispatcher .startBleScanWithCheck(this);

Slide 64

Slide 64 text

5. ͓͠·͍ ͏·͍͜ͱ΍ͬͯ͘ΕΔ

Slide 65

Slide 65 text

ૣ଎σόΠεΛ୳ͯ͠σʔλΛ औಘ͍ͨ͠ʂʂ ΍Δ͜ͱ 1. पғͷσόΠεΛεΩϟϯ͢Δ 2. ݟ͔ͭͬͨσόΠε಺ͷGATTαʔόʹ઀ଓ͢Δ 3. GATTαʔό͔ΒCSC ServiceΛऔಘ͢Δ 4. CSC Service͕࣋ͬͯΔCSC Measurement CharacteristicΛऔಘ 5. ߋ৽͕͋ͬͨΒ௨஌(Notification)ΛૹͬͯͶͱཁٻ͢Δ

Slide 66

Slide 66 text

1. ·ͣ͸εΩϟφʔΛ΋Β͏ // Bluetooth Service Λ΋Βͬͯ BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); // Bluetooth ΞμϓλΛ΋Βͬͯ BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter(); // Ξμϓλ͕࣋ͬͯΔ BLE ͷεΩϟφΛ΋Βͬͯ͘Δ bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();

Slide 67

Slide 67 text

ͰɺεΩϟϯ͢Δ // εΩϟϯઃఆ ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_BALANCED) // ଞLOW_LATENCYͱ͔ .build(); // CSC Service ͚ͩݟ͚ͭͯཉ͍͠ͷͰϑΟϧλΛઃఆ͢Δ List filters = new ArrayList<>(); filters.add(new ScanFilter.Builder() .setServiceUuid(new ParcelUuid(SERVICE_UUID)) .build()); // εΩϟϯΑΖ͘͠! bluetoothLeScanner.startScan(filters, settings, callback);

Slide 68

Slide 68 text

2. σόΠε಺ͷ GATT αʔό ʹ઀ଓ͢Δ @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); // CSC Service Λ࣋ͭσόΠε! BluetoothDevice device = result.getDevice(); // GATT αʔόʔʹܨ͍Ͱ͘Ε! BluetoothGatt gatt = device.connectGatt(context, false, new GattCallback()); } σόΠε͕ݟ͔ͭΔͱݺͼग़͞ΕΔίʔϧόοΫ಺ͰDPOOFDU(BUU͢Δɻ

Slide 69

Slide 69 text

4. ݟ͔ͭͬͨService͔Β͓໨౰ͯ ͷCharacteristicΛ΋Β͏ @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { BluetoothGattService service = gatt.getService(SERVICE_UUID); if (service != null) { characteristic = service.getCharacteristic(CHARACTERISTIC_UUID); Ұཡ͕औಘͰ͖ͨΒɺ$4$4FSWJDFΛऔಘͯ͠ɺ
 $4$.FBTVSFNFOU$IBSBDUFSJTUJDΛऔಘ

Slide 70

Slide 70 text

5. ௨஌ͯ͠ͶͬͯઃఆΛ͢Δ // 1. Bluetooth Stackʹड͚औͬͨΒίʔϧόοΫͯ͠Ͷ! ͬͯ఻͑Δ gatt.setCharacteristicNotification(characteristic, true); // 2. Device ʹ΋ߋ৽௨஌ͯ͘͠ΕΑͳ! ͬͯ఻͑Δ // (descriptorʹॻ͖ࠐΉͱૹ৴͞ΕΔ) final BluetoothGattDescriptor descriptor = characteristic.getDescriptor( CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); if (descriptor != null) { descriptor .setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); gatt.writeDescriptor(descriptor); }

Slide 71

Slide 71 text

σʔλऔಘ։࢝ʂ @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { // σʔλΛௐཧ͢Δ } PO$IBSBDUFSJTUJD$IBOHFE͕ݺͼग़͞ΕΔΑ͏ʹͳΔʂ
 ૹ৴ִؒ͸େମඵʹճ

Slide 72

Slide 72 text

σʔλΛௐཧ͢Δ • ΍ͬͯ͘Δσʔλ͸όΠτྻ • byte getValue() • όΠτྻΛ·Δͬͱฦ͢ • ಛఆͷόΠτΦϑηοτ͔Β೚ҙͷܕͰऔΓग़͢ ؔ਺͕༻ҙ͞ΕͯΔ • int getIntValue(formatType, offset)

Slide 73

Slide 73 text

CSC Measurement͕ૹΔσʔλ • ઌ಄͔Β • 1byte - flags (1: ϗΠʔϧ͋Δ͔, 2: ΫϥϯΫ͋Δ͔) • ϗΠʔϧ͋ΔͳΒ • uint32 ྦྷੵճసճ਺ • uint16 ࠷ޙͷΠϕϯτ͕͋ͬͨ࣌ؒ • ΫϥϯΫ͋ΔͳΒ • uint16 ྦྷੵճసճ਺ • uint16 ࠷ޙͷΠϕϯτ͕͋ͬͨ࣌ؒ

Slide 74

Slide 74 text

int offset = 0; byte flags = characteristic.getValue()[offset]; offset += 1; boolean wheelRevPresent = (flags & 1) > 0; boolean crankRevPreset = (flags & 2) > 0; if (wheelRevPresent) { int wheelRevolutions = characteristic.getIntValue( BluetoothGattCharacteristic.FORMAT_UINT32, offset); offset += 4; int wheelEventTime = characteristic.getIntValue( BluetoothGattCharacteristic.FORMAT_UINT16, offset); offset += 2; } if (crankRevPreset) { int crankRevolutions = characteristic.getIntValue( BluetoothGattCharacteristic.FORMAT_UINT16, offset); offset += 2; int crankEventTime = characteristic.getIntValue( BluetoothGattCharacteristic.FORMAT_UINT16, offset); offset += 2; }

Slide 75

Slide 75 text

औΕͨʂ • ճస਺ʹλΠϠͷܘΛֻ͚ͯ΍Ε͹଎౓͕ग़Δʂ • λΠϠͷܘ͸ 2096mm (700x23C)

Slide 76

Slide 76 text

࣍ɺը໘࡞ͬͯͧ͘ʂ

Slide 77

Slide 77 text

ը໘Λ࡞͍ͬͯͧ͘ • େલఏ: എܠ͸ࠇ • AMOLEDͩͱൃޫͯ͠Δ෦෼͔͠ిྗফඅ͠ͳ͍ • ϨΠΞ΢τ͸ ContraintLayout (Support Library) • ཁૉؒͰؔ܎ੑΛηοτ͍ͯ͘͠ • ৘ใΛิ׬͢ΔΞχϝʔγϣϯ • ਺ࣈΛग़͚ͩ͢Ͱͳ͘ɺಈ͖Ͱঢ়گΛ఻͑Δ • ઐ༻ͷViewΛ࡞Δ

Slide 78

Slide 78 text

ConstraintLayout

Slide 79

Slide 79 text

ConstraintLayout • ྫ: ୯Ґදࣔ • ࠨ୺Λ΄͔ͷߦͱἧ͑ͭͭ • ॎͷҐஔ͸ಉ͡ߦͷ਺஋ͷϕʔεϥΠϯʹἧ͑Δ • …ͳΜͯࢦఆ͕؆୯ʹͰ͖ͯΑ͍ • খ਺఺ҎԼͷද͚ࣔͩผͷ TextView ʹͯ͠ϑΥϯταΠζΛ খ͘͢͞Δ…ͳΜͯ΍ͬͯ΋มʹζϨͨΓ͠ͳ͍ • GUIͰҰ௨ΓઃఆͰ͖Δ͚Ͳɺͪΐͬͱෆ۩߹͋ͬͨΓ͢Δ ͷͰඍௐ੔͸XMLͰ΍Δ͔ͳʔͬͯײ͡

Slide 80

Slide 80 text

ValueAnimator • 1ඵʹ1ճདྷΔ਺ࣈΛ࣍ʑ setText() ͢Δ͚ͩ Ͱ΋͍͍͚Ͳɺຯؾͳ͍ • νϥݟͰ૿͑ͯΔͷ͔ݮͬͯΔͷ͔෼͔Βͳ͍ • ਺ࣈΛঃʑʹมԽͤ͞Δ

Slide 81

Slide 81 text

͜͏΍ͬͯ ValueAnimator animator = ValueAnimator.ofFloat(0.0f, 0.0f); animator.setDuration(1000); animator.setInterpolator(new LinearInterpolator()); animator.addUpdateListener((animation) -> { float value = (Float) animation.getAnimatedValue(); textView.setText(String.format(Locale.US, "%.1f", value)); });

Slide 82

Slide 82 text

஋͕͘Δͨͼʹɺݱࡏ஋
 →৽͍͠஋Ͱ setFloatValues ͢Δ private void setAnimatorValue(ValueAnimator animator, float newValue) { float currentValue = (Float) animator.getAnimatedValue(); animator.setFloatValues(currentValue, newValue); animator.start(); }

Slide 83

Slide 83 text

…ͱ1ඵؒͰ਺ࣈ͕௚ઢతʹ૿ݮ͢Δ Լʢճస਺ʣ͸ͦͷ··ɺ
 ্ʢεϐʔυʣ͕༗ޮʹͯ͠Δ΍ͭ

Slide 84

Slide 84 text

ͪͳΈʹ ValueAnimator • ඵؒ60ճݺͼग़͞Ε·͢ • ͪΐ͏Ͳ͍͍͚Ͳඞཁͳ͍ͱ͖͸ setText() ͠ͳ͍ͱ͔͢ΔͱΑ͍

Slide 85

Slide 85 text

ಠࣗͷViewΛ࡞ͬͯ഑ஔ͢Δ • ΋͏গ͠໘ന͍ද͕ࣔཉ͍͠ͳʔάϥϑͱ͔ • ৭ʑϥΠϒϥϦ͋Δ͚Ͳɺ؆୯ͳϞϊͩͬͨ Β࡞ͬͯ͠·ͬͨ΄͏͕͍ܰ଎͍

Slide 86

Slide 86 text

๮ͱɺ͘Δ͘Δ͢Δ΍ͭ

Slide 87

Slide 87 text

ॎઢҰຊͷ଎౓ϝʔλʔ (HorizontalBarGraphView) • Viewͷ෯ʹରͯ͠ݱࡏ஋ʹ౰ͨΔׂ߹ͷҐஔʹ ॎઢΛҾ͚͹Α͍ʂ • Ҏ্ͩʂ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int x = (int) ( (Math.min(current, max) - min) / (max - min) * canvas.getWidth() ); canvas.drawLine(x, 0, x, getHeight(), paint); }

Slide 88

Slide 88 text

͋ͱ͸஋Ληοτͯ͠ invalidate() public void setCurrent(float current) { this.current = current; invalidate(); }

Slide 89

Slide 89 text

͘Δ͘ΔճΔ΍ͭ (CircularRevolutionsView) • ࣮ࡍͷճసΛ࠶ݱ͢Δͱ͓΋͠Ζͦ͏ͩͳʁ • ValueAnimator Ͱ 0.0f → 1.0f ΛӬٱϧʔ ϓɺ 1 ճసʹ͔͚Δ࣌ؒ (duration) Λߋ৽͠ ͍ͯ͘ • ͋ͱ͸ԁΛඳ͘ɺεϜʔζʹճͯ͠΋͍͍͚ Ͳ45°ͣͭʹ͢ΔͱͦΕͬΆ͍͔ͳʁ

Slide 90

Slide 90 text

int centerX = width / 2 + x; int centerY = height / 2 + y; // ਅΜதͷখؙ͍͞ canvas.drawCircle(centerX, centerY, width / 16, paint); if (rpm != 0.0f) { // 1पΛ8ஈ֊ʹؙΊΔ int step = (int) ((Float) animator.getAnimatedValue() * 8); float degree = step / (float) split; // ͦͷҐஔʹؙΛඳ͘ canvas.drawCircle( centerX - (float) Math.cos(2 * Math.PI * degree) * (width / 2) * 0.75f, centerY - (float) Math.sin(2 * Math.PI * degree) * (height / 2) * 0.75f, width / 8, paint); }

Slide 91

Slide 91 text

݁Ռɺ͜͏ͳΓ·ͨ͠

Slide 92

Slide 92 text

৭ʑಈ͍ͯͨͷ͠ʔʂ

Slide 93

Slide 93 text

͢ΜͳΓͰ͖ͨΑ͏ʹ
 ݟ͑ΔͰ͠ΐ͏ʁ

Slide 94

Slide 94 text

΋ͪΖΜϋϚΓ·ͨ͠

Slide 95

Slide 95 text

Android 7.1.1
 Bluetoothܨ͕Βͳ͍໰୊ • ։ൃ͠Α͏ͱࢥͬͨΒಥવ͢΂ͯͷΞϓϦͰ ηϯαͷ஋ΛೝࣝͰ͖ͳ͘ͳͬͨ • ։ൃͰ͖ͳ͍… • 7.0.0ʹ໭ͨ͠Βܨ͕ͬͨ • 7.1.2Ͱ࣏ͬͯΔ໛༷

Slide 96

Slide 96 text

ߴ͕͞෼͔ΔΑ͏ʹͳͬͨ
 ࣌ͷ࿩

Slide 97

Slide 97 text

࣮ࡍʹ૸Δͧʂ …͋ΕΕߴ౓ͷ਺ࣈ͕શવ͓͔͍ͧ͠ʁ
 ؾѹηϯα͡Όμϝͳͷ͔ʁ

Slide 98

Slide 98 text

εϚϗϗϧμʔɺା…ʁ • ؾѹͱ͸ • ାʹѹഭ͞ΕΔ͚ͩͰߴ౓͕ٸ߱Լʙ • ͋ͱɺ൓ࣹͯ͠ɺݟ͑ͳ͍

Slide 99

Slide 99 text

վળ ାঢ়͡Όͳ͍Ϛ΢ϯτͰղܾ

Slide 100

Slide 100 text

ࢥ͍ࠐΈͰ࣌ؒϩε • ʮؾѹηϯαʔͩΊ͔ʔʯͱࢥ͍͜Μ͡Όͬͨ • ٸ͍Ͱ܏ࣼΛOrientation(ʹՃ଎౓ͱॏྗ)Ͱग़ͦ͏ͱࢼΈ ͨΓͨ͠ • ٸ͍Ͱίϐϖͯͦ͠ΕͬΆ͍ͷ͕Ͱ͖ͨʂ૸ͬͯΈΑ͏ʂʂ • ಈ͖ͩͨ͠ॠؒ஋͕ඈΜͰ͍͘… • Ճ଎౓ͷ஋Λॏྗͷ஋ͱֻ͚߹Θͤͯຊମͷ֯౓Λݕ஌͢Δ ࢓૊Έ • ಈ͍ͨΒਖ਼͘͠൑ఆͰ͖ͳ͍ͷ౰ͨΓલ͡ΌΜ…

Slide 101

Slide 101 text

ͳͲͳͲ͋Γ·͕ͨ͠

Slide 102

Slide 102 text

ݴ͍͔ͨͬͨ͜ͱ • ·ΘΓͷϞϊΛConnectedʹͯ͘͠ͱָ͍͠ • ࢥ͍ͬͯΔΑΓ͍ΖΜͳ΋ͷ͕Android͔Β ૢ࡞Ͱ͖ΔΑ͏ʹͳ͍ͬͯΔ

Slide 103

Slide 103 text

ࠓճ͸ࣗసं͚ͩͬͨͲՈి΋ • ྫ͑͹͓͏ͪʹ͋ΔSONYͷBRAVIA • IPΞυϨεΛϒϥ΢βͰ։͘

Slide 104

Slide 104 text

!?

Slide 105

Slide 105 text

ࢥΘ͵ॴʹ • API͕͋ͬͨΓ͢Δ • ಛʹެࣜͰެ։͞Εͯͳ͍͚Ͳ֤छݴޠͰϥΠϒϥϦ͕ ࣮૷͞ΕͯΔ • APIͳͯ͘΋੺֎ઢϦϞίϯ͋Δ΋ͷ͸IRKitͱ͔Ͱૢ࡞Ͱ ͖Δ • HTTPϦΫΤετ1ຊͰ͍ΖΜͳ΋ͷΛίϯτϩʔϧ • ࣗ෼ͷཉ͍͠Ϟϊͭ͘ΔͨΊʹ৭ʑܨ͍ͰΔ͚ͩͰݟ͑ͯ ͘Δੈք͕͋ΔΑʂ

Slide 106

Slide 106 text

·ͱΊ • Android BikeͬͯͷΛ΍ͬͯΈͨ • BLEͱ୺຤ͷηϯαΛ࢖ͬͨαΠίϯ࡞Δͷͨͷ͠ʔʂ • ࠓޙ΋ػೳ଍͍͖͍ͯͨ͠ • SDK࡞֦ͬͯுՄೳʹɺServiceԽɺ૸ͬͨه࿥Λอଘ (Google Fitͱ͔Stravaͱ͔)ɺࣗಈͰىಈͯ͠ه࿥։࢝ (Awareness API)ɺ௿ফඅిྗԽ • ΦʔϓϯιʔεͰ͢ʂʂʂϓϧϦΫΑΖ͘͠ʂʂʂʂʂ • https://github.com/tnj/android-bike-proto