Android 在google glass中实现低频实时卡

Android 在google glass中实现低频实时卡,android,google-glass,google-gdk,Android,Google Glass,Google Gdk,我尝试使用中提供的指令实现低频实时卡。 我有一个要呈现的布局和LiveCard服务类(扩展服务)。我还有Menu:activity来处理菜单回调,使菜单透明,并使用LiveCard服务中的setAction()为卡的操作提供一个PendingEvent 在将应用程序加载到Glass中时,我也收到了一条成功消息,但它没有显示在我的Glass中。 我不知道还缺什么 [2014-04-22 00:45:01 - MyApp] Installing MyApp.apk... [2014-04-22 00

我尝试使用中提供的指令实现低频实时卡。 我有一个要呈现的布局和LiveCard服务类(扩展服务)。我还有Menu:activity来处理菜单回调,使菜单透明,并使用LiveCard服务中的setAction()为卡的操作提供一个PendingEvent

在将应用程序加载到Glass中时,我也收到了一条成功消息,但它没有显示在我的Glass中。 我不知道还缺什么

[2014-04-22 00:45:01 - MyApp] Installing MyApp.apk...
[2014-04-22 00:45:04 - MyApp] Success!
[2014-04-22 00:45:04 - MyApp] /MyApp/bin/MyApp.apk installed on     device
[2014-04-22 00:45:04 - MyApp] Done!
以下是我的LiveCard服务:

public class LiveCardService extends Service {
private ArrayList<FeedItem> feedItems = new ArrayList<FeedItem>();
//private FeedAdapter feedAdapter = null;

// NYC: 40.758895, -73.985131
private double latitude = 0;
private double longitude = 0;

private LocationManager mlocManager;
private LocationListener mlocListener;
/******/

private static final String LIVE_CARD_TAG = "LiveCardDemo";

//private TimelineManager mTimelineManager;
private LiveCard mLiveCard;
private RemoteViews mLiveCardView;

private int homeScore, awayScore;
private Random mPointsGenerator;

private final Handler mHandler = new Handler();
private final UpdateLiveCardRunnable mUpdateLiveCardRunnable =
    new UpdateLiveCardRunnable();
private static final long DELAY_MILLIS = 30000;

@Override
public void onCreate() {
    super.onCreate();
    //mTimelineManager = TimelineManager.from(this);
    mPointsGenerator = new Random();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    if (mLiveCard == null) {

        // Get an instance of a live card
       // mLiveCard = mTimelineManager.createLiveCard(LIVE_CARD_TAG);
        mLiveCard = new LiveCard(this, LIVE_CARD_TAG);

        // Inflate a layout into a remote view
        mLiveCardView = new RemoteViews(getPackageName(),
            R.layout.score);

        mLiveCard.setViews(mLiveCardView); // !!!

      // Set up initial RemoteViews values
        homeScore = 0;
        awayScore = 0;
        /**/
        mLiveCardView.setTextViewText(R.id.homeTeamNameTextView,
                /*getString(R.id.home_team)*/"HOME TEAM");
        mLiveCardView.setTextViewText(R.id.awayTeamNameTextView,
                /*getString(R.id.away_team)*/"AWAY TEAM NAME");
        mLiveCardView.setTextViewText(R.id.footer_text,
                /*getString(R.id.game_quarter)*/"FOOTER_TEXT");
        /**/

        // Set up the live card's action with a pending intent
        // to show a menu when tapped
        Intent menuIntent = new Intent(this, MenuActivity.class);
        menuIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
            Intent.FLAG_ACTIVITY_CLEAR_TASK);
        mLiveCard.setAction(PendingIntent.getActivity(
            this, 0, menuIntent, 0));

        // Publish the live card
        mLiveCard.publish(PublishMode.REVEAL);

        // Queue the update text runnable
        mHandler.post(mUpdateLiveCardRunnable);
    }
    return START_STICKY;
}

@Override
public void onDestroy() {
    if (mLiveCard != null && mLiveCard.isPublished()) {
      //Stop the handler from queuing more Runnable jobs
        mUpdateLiveCardRunnable.setStop(true);

        mLiveCard.unpublish();
        mLiveCard = null;
    }
    super.onDestroy();
}

/**
 * Runnable that updates live card contents
 */
private class UpdateLiveCardRunnable implements Runnable{

    private boolean mIsStopped = false;

    /*
     * Updates the card with a fake score every 30 seconds as a demonstration.
     * You also probably want to display something useful in your live card.
     *
     * If you are executing a long running task to get data to update a
     * live card(e.g, making a web call), do this in another thread or
     * AsyncTask.
     */
    public void run(){
        if(!isStopped()){
          // Generate fake points.
            homeScore += mPointsGenerator.nextInt(3);
            awayScore += mPointsGenerator.nextInt(3);

            // Update the remote view with the new scores.
            mLiveCardView.setTextViewText(R.id.home_score_text_view,
                String.valueOf(homeScore));
            mLiveCardView.setTextViewText(R.id.away_score_text_view,
                String.valueOf(awayScore));

            // Always call setViews() to update the live card's RemoteViews.
            mLiveCard.setViews(mLiveCardView);

            // Queue another score update in 30 seconds.
            mHandler.postDelayed(mUpdateLiveCardRunnable, DELAY_MILLIS);
        }
    }

    public boolean isStopped() {
        return mIsStopped;
    }

    public void setStop(boolean isStopped) {
        this.mIsStopped = isStopped;
    }
}

@Override
public IBinder onBind(Intent intent) {
  /*
   *  If you need to set up interprocess communication
   * (activity to a service, for instance), return a binder object
   * so that the client can receive and modify data in this service.
   *
   * A typical use is to give a menu activity access to a binder object
   * if it is trying to change a setting that is managed by the live card
   * service. The menu activity in this sample does not require any
   * of these capabilities, so this just returns null.
   */
    return null;
}
公共类LiveCardService扩展服务{
private ArrayList feedItems=新建ArrayList();
//专用FeedAdapter=null;
//纽约市:40.758895,-73.985131
私人双纬度=0;
私人双经度=0;
私人场所经理;
私有位置侦听器mlocListener;
/******/
私有静态最终字符串LIVE\u CARD\u TAG=“LiveCardDemo”;
//私人TimelineManager MTTimeLineManager;
私人生活卡;
私有远程视图;
私人int homeScore、awayScore;
私有随机mPointsGenerator;
私有最终处理程序mHandler=新处理程序();
私有最终更新CardRunnable mUpdateLiveCardRunnable=
新的UpdateLiveCardRunnable();
专用静态最终长延迟_MILLIS=30000;
@凌驾
public void onCreate(){
super.onCreate();
//mTimelineManager=TimelineManager.from(this);
mPointsGenerator=新随机数();
}
@凌驾
公共int onStartCommand(Intent Intent、int标志、int startId){
如果(mLiveCard==null){
//获取实时卡的实例
//mLiveCard=mTimelineManager.createLiveCard(LIVE_CARD_标记);
mLiveCard=新的LiveCard(这是LiveCard标签);
//将布局充气到远程视图中
mLiveCardView=新的远程视图(getPackageName(),
R.布局、得分);
设置视图(mLiveCardView);/!!!
//设置初始RemoteView值
homeScore=0;
awayScore=0;
/**/
mLiveCardView.setTextViewText(R.id.homeTeamNameTextView,
/*getString(R.id.home_team)*/“home team”);
mLiveCardView.setTextViewText(R.id.awayTeamNameTextView,
/*getString(R.id.客场球队)*/“客场球队名称”);
mLiveCardView.setTextViewText(R.id.footer\u text,
/*getString(R.id.game\u quarter)*/“FOOTER\u TEXT”);
/**/
//设置具有挂起意图的live卡操作
//点击时显示菜单
Intent menuIntent=新的Intent(这是MenuActivity.class);
menuIntent.addFlags(Intent.FLAG\u活动\u新任务|
意图。标记活动(清除任务);
mLiveCard.setAction(PendingEvent.getActivity(
这个,0,menuIntent,0);
//发布实时卡
mLiveCard.publish(PublishMode.discover);
//将更新文本排入可运行队列
mHandler.post(mUpdateLiveCardRunnable);
}
返回开始时间;
}
@凌驾
公共空间{
如果(mLiveCard!=null&&mLiveCard.isPublished()){
//停止处理程序对更多可运行作业排队
mupdatalevecardrunnable.setStop(true);
mLiveCard.unpublish();
mLiveCard=null;
}
super.ondestory();
}
/**
*Runnable,用于更新实时卡内容
*/
私有类UpdateLiveCardRunnable实现Runnable{
私有布尔值=false;
/*
*每30秒用假分数更新卡片,作为演示。
*您可能还希望在live card中显示一些有用的内容。
*
*如果您正在执行长时间运行的任务以获取数据以更新
*实时卡(例如,拨打网络电话),在另一个线程或
*异步任务。
*/
公开募捐{
如果(!isStopped()){
//生成假点。
homeScore+=mPointsGenerator.nextInt(3);
awayScore+=mPointsGenerator.nextInt(3);
//用新分数更新远程视图。
mLiveCardView.setTextViewText(R.id.home\u score\u text\u视图,
String.valueOf(homeScore));
mLiveCardView.setTextViewText(R.id.away\U score\U text\U视图,
字符串.valueOf(awayScore));
//始终调用setViews()以更新live卡的RemoteView。
设置视图(mLiveCardView);
//在30秒内排队等待另一个分数更新。
mHandler.postDelayed(可运行多个卫星卡,延迟为毫秒);
}
}
公共布尔值(){
返回错误;
}
公共无效设置停止(布尔值){
this.missstopped=isStopped;
}
}
@凌驾
公共IBinder onBind(意向){
/*
*如果需要设置进程间通信
*(例如,服务的活动)返回绑定器对象
*以便客户端可以接收和修改此服务中的数据。
*
*一个典型的用法是为菜单活动提供对活页夹对象的访问权限
*如果试图更改由live卡管理的设置
*服务。此示例中的菜单活动不需要任何
*这只是返回null。
*/
返回null;
}
这是我的清单文件

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.coeverywhere.google_glass"
android:versionCode="5"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="15"
    android:targetSdkVersion="15" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="com.google.android.glass.permission.DEVELOPMENT" />

<application
    android:allowBackup="true"
    android:icon="@drawable/mylogo"
    android:label="@string/app_name">
    <activity
        android:name="com.myapp.google_glass.MenuActivity"
        android:theme="@style/MenuTheme"
        android:enabled="true"
        >
    </activity>

    <!--  android:icon="@drawable/ic_lap" -->
    <service
        android:name="com.myapp.google_glass.LiveCardService"    
        android:label="@string/app_name"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
        </intent-filter>
        <meta-data
            android:name="com.google.android.glass.VoiceTrigger"
            android:resource="@xml/voice_trigger_start" />
    </service>

</application>

</manifest>

这是我的voice\u trigger\u start.xml。我把它们放在res/xml下

<?xml version="1.0" encoding="utf-8"?>
<trigger command = "basketball" />

以下是原始答案,此后我制作了一个参考项目,该项目采用谷歌文档,并使用秒表项目作为参考更新XE16。查看代码并提交历史记录以了解更多信息:

一种方法是声明一个语音触发器来启动服务/livecard

此模式说明中提到了这一点:

这里描述了该技术:

我用你的代码测试了它,如果清单中有这些项,它就可以工作了(当然要修改你的包名)…这是第一个
        <service
        android:name="com.example.lowfrequencylivecardexample.LiveCardService"
        android:enabled="true"
        android:exported="true"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
        </intent-filter>
        <meta-data
            android:name="com.google.android.glass.VoiceTrigger"
            android:resource="@xml/voice_trigger" />
    </service>
    <uses-permission android:name="com.google.android.glass.permission.DEVELOPMENT" />
<?xml version="1.0" encoding="utf-8"?>
<trigger keyword="basketball" />