Skip to content

Commit

Permalink
Merge branch 'microsoft:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
CarlosP-MS authored Dec 2, 2024
2 parents ad075d6 + 3e230f2 commit 149bacf
Show file tree
Hide file tree
Showing 385 changed files with 14,412 additions and 3,473 deletions.
65 changes: 65 additions & 0 deletions .github/workflows/build-docker-container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

# This workflow builds a Docker container and deploys it to the TypeAgent container repository

name: Build and deploy Node.js app to Azure Web App - typeagent

on:
push:
branches:
- main
workflow_dispatch:

permissions:
id-token: write
contents: read

jobs:

deploy:
runs-on: ubuntu-latest # pnpm deploy does not work currently on Windows. Fails with EPERM.
steps:
- name: Setup Git LF
run: |
git config --global core.autocrlf false
- uses: actions/checkout@v4
with:
ref: main

- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
ts:
- "ts/**"
- ".github/workflows/build-ts.yml"
- uses: pnpm/action-setup@v4
if: ${{ github.event_name != 'pull_request' || steps.filter.outputs.ts == 'true' }}
name: Install pnpm
with:
version: 9
run_install: false

- uses: actions/setup-node@v4
if: ${{ github.event_name != 'pull_request' || steps.filter.outputs.ts == 'true' }}
with:
node-version: ${{ matrix.version }}
#cache: "pnpm"
#cache-dependency-path: ts/pnpm-lock.yaml

- name: Login to Azure
uses: azure/login@v2.2.0
with:
client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_5B0D2D6BA40F4710B45721D2112356DD }}
tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_39BB903136F14B6EAD8F53A8AB78E3AA }}
subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_F36C1F2C4B2C49CA8DD5C52FAB98FA30 }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- run: az acr build -t typeagent:latest -r typeagentContainerRegistry --file ${{ github.workspace }}/ts/Dockerfile --subscription b64471de-f2ac-4075-a3cb-7656bca768d0 ${{ github.workspace }}/ts


1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -437,3 +437,4 @@ FodyWeavers.xsd

# Python virtual env
.venv
android/samples/mobile/.idea/deploymentTargetSelector.xml
File renamed without changes.
File renamed without changes.
File renamed without changes.
18 changes: 18 additions & 0 deletions android/samples/mobile/.idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
File renamed without changes.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ plugins {

android {
namespace = "com.microsoft.typeagent.sample"
compileSdk = 34
compileSdk = 35

defaultConfig {
applicationId = "com.microsoft.typeagent.sample"
minSdk = 33
targetSdk = 34
targetSdk = 35
versionCode = 1
versionName = "1.0"

Expand Down Expand Up @@ -50,7 +50,6 @@ android {
}

dependencies {

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
Expand All @@ -59,6 +58,8 @@ dependencies {
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
implementation(libs.androidx.webkit)
implementation(libs.simple.android.bridge)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
Expand Down
File renamed without changes.
71 changes: 71 additions & 0 deletions android/samples/mobile/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.hardware.camera" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- <uses-permission android:name="android.webkit.PermissionRequest" />-->
<!-- <uses-permission android:name="android.webkit.resource.AUDIO_CAPTURE" />-->
<!-- <uses-permission android:name="android.webkit.resource.VIDEO_CAPTURE" />-->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="true" />
<uses-feature android:name="android.hardware.camera.front" android:required="true" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.camera.level.full" android:required="true" />
<uses-feature android:name="android.hardware.camera.capability.raw" android:required="true" />
<uses-feature android:name="android.hardware.camera.any" android:required="true" />
<uses-feature android:name="android.hardware.microphone" android:required="true" />
<uses-feature android:name="android.hardware.camera2" android:required="true" />



<uses-feature
android:name="android.hardware.telephony"
android:required="false" />

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.TypeAgentAndroidSample"
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.TypeAgentAndroidSample">

<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<!-- Intent filter for launching the from other apps via intents -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<data android:scheme="typeagent" android:host="main" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>


</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package com.microsoft.typeagent.sample

import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.provider.AlarmClock
import android.util.Log
import android.webkit.JavascriptInterface
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.startActivities
import androidx.core.content.ContextCompat.startActivity
import de.andycandy.android.bridge.CallType
import de.andycandy.android.bridge.DefaultJSInterface
import de.andycandy.android.bridge.JSFunctionWithArg
import de.andycandy.android.bridge.NativeCall
import de.andycandy.android.bridge.Promise
import java.time.LocalDateTime
import java.util.Locale
import java.util.concurrent.locks.Condition

typealias SpeechRecognitionCallback = (String) -> Void;


class JavaScriptInterface(var context: Context) : DefaultJSInterface("Android") {

public var speechCallback: SpeechRecognitionCallback? = null
public var speechPromise: Promise<String?>? = null
private var recoId: Int = 0
private val recoLocks: MutableMap<Int, Condition> = mutableMapOf()
private val recoCallbacks: MutableMap<Int, JSFunctionWithArg<String?>> = mutableMapOf()

@JavascriptInterface
fun showToast(message: String) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}

//@JavascriptInterface
fun startIntent() {
val latitude = 45.03923F
val longitude = 122.12343F
val uri = String.format(Locale.ROOT, "geo:%f,%f", latitude, longitude)
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(uri))
startActivity(context, intent, null)
}

@JavascriptInterface
fun setAlarm(time: String) {
Log.i("javascript", "setAlarm")
val t: LocalDateTime = LocalDateTime.parse(time);
val intent = Intent(AlarmClock.ACTION_SET_ALARM)
.putExtra(AlarmClock.EXTRA_HOUR, t.hour)
.putExtra(AlarmClock.EXTRA_MINUTES, t.minute)
startActivity(context, intent, null)
}

@JavascriptInterface
fun callPhoneNumber(phoneNumber: String) {
Log.i("javascript", "callPhoneNumber")
val uri = String.format(Locale.ROOT, "tel:%s", phoneNumber)
val intent = Intent(Intent.ACTION_CALL, Uri.parse(uri))
startActivity(context, intent, null);
}

@JavascriptInterface
fun sendSMS(phoneNumber: String, message: String) {
Log.i("javascript", "sendSMS")
val uri = String.format(Locale.ROOT, "smsto:%s", phoneNumber)
val intent = Intent(Intent.ACTION_SENDTO, Uri.parse(uri))
.putExtra("sms_body", message);
startActivity(context, intent, null)
}

@JavascriptInterface
fun searchNearby(searchTerm: String) {
Log.i("javascript", "searchNearby")
val uri = Uri.parse("geo:0,0?q=$searchTerm")
val intent = Intent(Intent.ACTION_VIEW, uri)
intent.setPackage("com.google.android.apps.maps")
startActivity(context, intent, null)
}

@JavascriptInterface
fun isSpeechRecognitionSupported(): Boolean {
return PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(context, android.Manifest.permission.RECORD_AUDIO)
}

@JavascriptInterface
fun automateUI(prompt: String) {
Log.i("javascript", "automateUI")
val uri = Uri.parse("maia://main?execute=true&prompt=${prompt}")
val intent = Intent(Intent.ACTION_VIEW)
.setData(uri)
.putExtra("prompt", prompt)
.addCategory(Intent.CATEGORY_BROWSABLE)
context.startActivity(intent)
}

/**
* Called by the client once the app has fully loaded
* TypeScript types in lib.android.d.ts as Bridge.interfaces.Android.domReady()
*/
@NativeCall(CallType.FULL_SYNC)
fun domReady(callback: JSFunctionWithArg<String>?) {
// if there's an initial prompt we should send that here
if (callback != null) {
MainActivity.currentActivity!!.prompt?.let { callback.call(it) }
}
}

/**
* Starts a recognition request, awaits the result and returns the result as a promise
* TypeScript types in lib.android.d.ts as Bridge.interfaces.Android.recognize()
*/
@NativeCall(CallType.FULL_SYNC)
fun recognize(callback: JSFunctionWithArg<String?>) {
// set speech callback
val id = ++recoId;
recoCallbacks[id] = callback

// start speech reco
MainActivity.currentActivity!!.speechToText(id)
}

/**
* Calls recognition callbacks
*/
fun recognitionComplete(id: Int, text: String?) {
if (recoCallbacks.containsKey(id)) {
recoCallbacks[id]!!.call(text)
recoLocks.remove(id)
}
}
}
Loading

0 comments on commit 149bacf

Please sign in to comment.