Skip to Content

/wp-content/uploads/2015/09/d_shop_blog_logo_788674.jpg

If you are an SAP Employee, please follow us on Jam.

Even when Google Glass is no more…at least not for individuals…I thought that connecting it to SAP HANA would make for a nice blog…because after all we have one at the d-shop…so here we go -;)

Glass_Logo.jpg

First, we need to create a Calculation View and call it “FLIGHTS_BY_CARRIER”. It will be composed of two tables, SCARR and SFLIGHT.

First, we need to create a Join object and link the table by MANDT and CARRID. From here select the following fields as output MANDT, CARRID, CARRNAME, PRICE and CURRENCY.

Then create an Aggregation object selecting the fields CARRNAME, PRICE (As Aggregated Column) and CURRENCY. Filter the CURRENCY field by ‘USD’.

Then create a Projection object and select only PRICE and CARRNAME.


On the Semantics object make sure to select “CROSS CLIENT” as the Default Client.

Calculation_View.jpg

Now, switch to the SAP HANA Development View and create a new repository. Call it “Flights”.

Create a new “XS Engine” project and call it “Flights” as well. Link it to the “Flights” repository.

Create an empty “.xsapp” file.

Create a file called “.xsaccess” with the following code.

.xsaccess

{

“exposed” : true,

“authentication” : [ { “method” : “Basic” } ]

}

Finally create a file called “flights.xsodata” with the following code

flights.xsodata

service {

          “Blag/FLIGHTS_BY_CARRIER.calculationview” as “FLIGHTS” keys generate local “Id”;

  }

Activate your project and launch it on your browser, you should see something like this…


XSProject.jpg

The SAP HANA part is done…so we can move into the Google Glass part…

First, download Android Studio and update your SDK Manager to include the following…API 19 including Google Glass Kit Preview.

SDK_Manager.jpg

Create a new project and call it “GLASS_HANA” or whatever you fancy…

Create_Project.jpg

On the next screen, uncheck “Phone and Tablet” and check “Glass”. Make sure that “Glass Development Kit Preview (API 19) is selected.

Glass_Development.jpg

Choose “Immersion Activity”.

Activity.jpg

Leave the “MainActiviy” name and change the Activity Name if you want.

MainActivity.jpg

On the “MainActivity” file copy the following code

Main Activity

package glass.app.com.flightsreport;

import com.google.android.glass.media.Sounds;

import com.google.android.glass.widget.CardBuilder;

import com.google.android.glass.widget.CardScrollAdapter;

import com.google.android.glass.widget.CardScrollView;

import android.app.Activity;

import android.content.Context;

import android.media.AudioManager;

import android.os.Bundle;

import android.view.View;

import android.view.ViewGroup;

import android.widget.AdapterView;

import com.android.volley.RequestQueue;

import com.android.volley.toolbox.Volley;

import android.speech.RecognizerIntent;

import android.speech.tts.TextToSpeech;

public class MainActivity extends Activity {

    /**

     * {@link CardScrollView} to use as the main content view.

     */

    private CardScrollView mCardScroller;

    private TextToSpeech mTTS;

    private RequestQueue mQueue;

    /**

     * “Hello World!” {@link View} generated by {@link #buildView()}.

     */

    private View mView;

    @Override

    protected void onCreate(Bundle bundle) {

        super.onCreate(bundle);

        mView = buildView();

        mCardScroller = new CardScrollView(this);

        mCardScroller.setAdapter(new CardScrollAdapter() {

            @Override

            public int getCount() {

                return 1;

            }

            @Override

            public Object getItem(int position) {

                return mView;

            }

            @Override

            public View getView(int position, View convertView, ViewGroup parent) {

                return mView;

            }

            @Override

            public int getPosition(Object item) {

                if (mView.equals(item)) {

                    return 0;

                }

                return AdapterView.INVALID_POSITION;

            }

        });

        // Handle the TAP event.

mCardScroller.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override

            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                // Plays disallowed sound to indicate that TAP actions are not supported.

                AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

am.playSoundEffect(Sounds.DISALLOWED);

            }

        });

        setContentView(mCardScroller);

    }

    @Override

    protected void onResume() {

        super.onResume();

        mCardScroller.activate();

    }

    @Override

    protected void onPause() {

        mCardScroller.deactivate();

        mTTS.shutdown();

        super.onPause();

    }

    /**

     * Builds a Glass styled “Hello World!” view using the {@link CardBuilder} class.

     */

    private View buildView() {

        mTTS = new TextToSpeech(this, new TextToSpeech.OnInitListener() {

@Override

            public void onInit(int status) {

            }

        });

        final CardBuilder card = new CardBuilder(this, CardBuilder.Layout.TEXT);

        mQueue = Volley.newRequestQueue(this);

        final String carrName = getIntent().getExtras().getStringArrayList(RecognizerIntent.EXTRA_RESULTS).get(0);

        HANAFlightsAPI.getFlightsData(carrName, mQueue, new HANAFlightsAPI.Callback() {

            @Override

            public void onFlightsData(HANAFlightsAPI.FlightsData flightsData) {

card.setText(flightsData.price);

card.setFootnote(flightsData.carrierName);

                setContentView(card.getView());

            }

        });

        return card.getView();

    }

  }

Create a new file and call it “HANAFlightsAPI” and copy the following code

HANAFlightsAPI

package glass.app.com.flightsreport;

import android.util.Log;

import com.android.volley.RequestQueue;

import com.android.volley.Response;

import com.android.volley.VolleyError;

import com.android.volley.toolbox.JsonObjectRequest;

import org.json.JSONException;

import org.json.JSONObject;

import android.util.Base64;

import java.util.HashMap;

import java.util.Map;

import com.android.volley.AuthFailureError;

import java.net.URI;

import java.net.URISyntaxException;


public class HANAFlightsAPI {

    /**

     * Open Weather Map API Endpoint

     */

    public static final String URL = “http://yourserver:8000/Flights/flights.xsodata/FLIGHTS?$format=json&$filter=CARRNAME%20eq%20“;

    /**

     * Object containing qualitative description of weather as well as temperature in Fahrenheit.

     */

    public static class FlightsData {

        public final String carrierName;

        public final String price;

        public FlightsData(String carrierName, String price) {

            this.carrierName = carrierName;

            this.price = price;

        }

    }

    public interface Callback {

        void onFlightsData(FlightsData flightsData);

    }

    public static void getFlightsData(String carrierName, RequestQueue queue, final Callback callback) {

        URI uri = null;

        try {

            uri = new URI(carrierName.replaceAll(” “, “%20”));

        } catch (URISyntaxException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        queue.add(new JsonObjectRequest(URL + “%27” + uri + “%27”, null,

                new Response.Listener<JSONObject>() {

                    @Override

                    public void onResponse(JSONObject response) {

                        String carrier = “”;

                        String price = “”;

                        try {

                            JSONObject results = (JSONObject) response.getJSONObject(“d”).getJSONArray(“results”).get(0);

                            carrier = results.getString(“CARRNAME”);

                            price = results.getString(“PRICE”);

                        } catch (JSONException e) {

e.printStackTrace();

                        }

callback.onFlightsData(new FlightsData(carrier, price));

                    }

                }, new Response.ErrorListener() {

            @Override

            public void onErrorResponse(VolleyError error) {

Log.e(“onErrorResponse”, error.getMessage());

            }

        }) {

            @Override

            public Map<String, String> getHeaders() throws AuthFailureError {

                HashMap<String, String> headers = new HashMap<String, String>();

                String creds = String.format(“%s:%s”, “YourUserName”, “YourPassword”);

                String auth = “Basic ” + Base64.encodeToString(creds.getBytes(), Base64.DEFAULT);

headers.put(“Authorization”, auth);

                return headers;

            }

        });

    }

  }

Go the second build.gradle file (the one that says “Module.app”) and add this…


Module.app

dependencies {

    compile fileTree(dir: ‘libs’, include: [‘*.jar’])

    compile ‘com.mcxiaoke.volley:library:1.0.+’

    androidTestCompile ‘org.hamcrest:hamcrest-all:1.3’

  }


This will add the Volley library which is an HTTP library designed to make Android apps networking easier and faster.

Open the file “voice_trigger.xml” and copy the following code

voice_trigger.xml

<?xml version=”1.0″ encoding=”utf-8″?>

<trigger keyword=”Flight Report”>

    <input prompt=”Which Carrier?”/>

</trigger>

Open the file “strings.xml” and copy the following code

strings.xml

<?xml version=”1.0″ encoding=”utf-8″?>

<resources>

    <string name=”app_name”>Flights Report</string>

    <string name=”glass_voice_trigger”>flights report</string>

    <string name=”glass_voice_prompt”>which carrier?</string>

</resources>

Open the file “AndroidManifest.xml” and copy the following code


AndroidManifest.xml

<?xml version=”1.0″ encoding=”utf-8″?>

<manifest xmlns:android=”http://schemas.android.com/apk/res/android

package=”glass.app.com.flightsreport”>

    <uses-permission android:name=”com.google.android.glass.permission.DEVELOPMENT”/>

    <uses-permission android:name=”android.permission.INTERNET”/>

    <application

        android:allowBackup=”true”

android:icon=”@drawable/ic_launcher”

        android:label=”Flights Report”>

        <activity android:name=”.MainActivity”>

            <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”/>

        </activity>

    </application>

  </manifest>


We’re almost ready…we need to connect our Google Glass and make sure it’s on Debug On.


Navigate to “Settings” and enter it.

Glass_Settings.jpg

Navigate to “Device info” and click it

Glass_DeviceInfo.jpg

Navigate to “Turn on debug” and click it. It should become “Turn off debug”


Glass_Debug.jpg


With that we will be able to link our Google Glass to our Android Studio project. Simply run it and you will see this on the Glass.

Flight_Report.jpg

Click to enter it and you will see the main screen



Flight_Report_Carrier.jpg


Say a carrier name like “American Airlines”


Flight_Report_AA.jpg

Wait and the application will connect to our SAP HANA OData and display the result

Flight_Report_AA_Result.jpg

Now, to not make you believe that I’m just making this up…try another one…like “Lufthansa”

Flight_Report_Lufthansa.jpg

Wait to see the result…


Flight_Report_Lufthansa_Result.jpg


Cool, huh? You could also ask for “Delta Airlines” or “United Airlines”…if you ask for something else, it might give you back the result for the most approximate name or just the default one.

I’m happy enough with this little project -;)

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply