Commit 96c13761 authored by Andreas Schildbach's avatar Andreas Schildbach
Browse files

Installer for card10 apps.

For now, it registers on the 'application/x.card10.app' MIME type and downloads from there.
The actual install to the card10 is todo.
parent d6d24a3a
......@@ -33,4 +33,6 @@ dependencies {
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.squareup.okhttp3:okhttp:4.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
}
......@@ -13,11 +13,17 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<data android:mimeType="application/x.card10.app"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
</manifest>
......@@ -21,11 +21,14 @@ import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothGattCharacteristic
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import de.ccc.events.badge.card10.installer.InstallerFragment
import de.ccc.events.badge.card10.scanner.ScannerFragment
import java.util.*
......@@ -121,7 +124,11 @@ class MainActivity : AppCompatActivity() {
fun permissionGranted() {
var fragment = supportFragmentManager.findFragmentById(R.id.fragment_container)
if (fragment == null) {
fragment = ScannerFragment()
// this dispatcher is a very rough first cut
if (intent.action == "application/x.card10.app")
fragment = InstallerFragment()
else
fragment = ScannerFragment()
supportFragmentManager.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit()
......
/*
* Copyright by the original author or authors.
*
* 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 de.ccc.events.badge.card10.installer;
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.UiThread
import androidx.annotation.WorkerThread
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import de.ccc.events.badge.card10.R
import kotlinx.android.synthetic.main.installer_fragment.*
import okhttp3.*
import okhttp3.HttpUrl.Companion.toHttpUrl
import java.io.IOException
class InstallerFragment : Fragment(), Callback {
val viewModel: InstallerViewModel by lazy { ViewModelProviders.of(this).get(InstallerViewModel::class.java) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.url.observe(
this,
Observer { url -> installer_fragment_url.text = "Installing card10 app from ${url}" })
viewModel.appBytes.observe(
this,
Observer { bytes -> installer_fragment_app.text = "${bytes.size} bytes loaded" })
viewModel.message.observe(this, Observer { message -> installer_fragment_message.text = message })
val url = activity!!.intent.data.toString().toHttpUrl()
viewModel.url.value = url
startDownload(url)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.installer_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
}
@WorkerThread
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
activity!!.runOnUiThread {
downloadSuccessful(response.body!!.bytes())
}
} else {
viewModel.message.postValue("${response.code} ${response.message}")
}
}
@WorkerThread
override fun onFailure(call: Call, e: IOException) {
viewModel.message.postValue(e.toString())
}
@UiThread
fun startDownload(url: HttpUrl) {
val request = Request.Builder()
.url(url)
.build()
val client = OkHttpClient()
client.newCall(request).enqueue(this)
viewModel.message.value = "Downloading…"
}
@UiThread
fun downloadSuccessful(appBytes: ByteArray) {
viewModel.appBytes.value = appBytes
viewModel.message.value = null
// TODO upload to card10
}
}
/*
* Copyright by the original author or authors.
*
* 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 de.ccc.events.badge.card10.installer
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import okhttp3.HttpUrl
class InstallerViewModel : ViewModel() {
val url = MutableLiveData<HttpUrl>()
val appBytes = MutableLiveData<ByteArray>()
val message = MutableLiveData<String>()
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_gravity="center_horizontal"
android:padding="16dp"
>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/installer_fragment_url"/>
<TextView android:layout_width="wrap_content"
android:layout_height="0px" android:layout_weight="1" android:id="@+id/installer_fragment_app"/>
<TextView android:layout_width="wrap_content" android:textStyle="bold"
android:layout_height="wrap_content" android:id="@+id/installer_fragment_message"/>
</LinearLayout>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment