From 024ceded996e5d270e92946fcecc233ae31bbcfe Mon Sep 17 00:00:00 2001 From: Vish Date: Sun, 6 Dec 2015 12:39:48 -0500 Subject: [PATCH 01/15] updates to Enabler app to include Dweet.io integration --- .../com/openxc/enabler/SettingsActivity.java | 39 +- .../DweetingPreferenceManager.java | 84 ++ .../preferences/PreferenceManagerService.java | 9 +- enabler/src/main/res/values/strings.xml | 5 + .../main/res/xml/recording_preferences.xml | 14 + library/src/main/assets/adjectives.txt | 1133 +++++++++++++++++ library/src/main/assets/nouns.txt | 982 ++++++++++++++ .../java/com/buglabs/dweetlib/DweetLib.java | 342 +++++ .../main/java/com/openxc/sinks/DweetSink.java | 157 +++ library/src/main/res/values/strings.xml | 2 + 10 files changed, 2758 insertions(+), 9 deletions(-) create mode 100644 enabler/src/main/java/com/openxc/enabler/preferences/DweetingPreferenceManager.java create mode 100644 library/src/main/assets/adjectives.txt create mode 100644 library/src/main/assets/nouns.txt create mode 100644 library/src/main/java/com/buglabs/dweetlib/DweetLib.java create mode 100644 library/src/main/java/com/openxc/sinks/DweetSink.java diff --git a/enabler/src/main/java/com/openxc/enabler/SettingsActivity.java b/enabler/src/main/java/com/openxc/enabler/SettingsActivity.java index f9ddc3147..90c916406 100644 --- a/enabler/src/main/java/com/openxc/enabler/SettingsActivity.java +++ b/enabler/src/main/java/com/openxc/enabler/SettingsActivity.java @@ -1,10 +1,5 @@ package com.openxc.enabler; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.bluetooth.BluetoothAdapter; @@ -39,6 +34,11 @@ import com.openxc.sinks.UploaderSink; import com.openxcplatform.enabler.R; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + /** * Initialize and display all preferences for the OpenXC Enabler application. * @@ -62,6 +62,7 @@ public class SettingsActivity extends PreferenceActivity { private ListPreference mVehicleInterfaceListPreference; private ListPreference mBluetoothDeviceListPreference; private CheckBoxPreference mUploadingPreference; + private CheckBoxPreference mDweetingPreference; private Preference mTraceFilePreference; private EditTextPreference mNetworkHostPreference; private EditTextPreference mNetworkPortPreference; @@ -101,6 +102,7 @@ private void initializeLegacyLayout() { if(action.equals(RECORDING_PREFERENCE)) { addPreferencesFromResource(R.xml.recording_preferences); initializeUploadingPreferences(getPreferenceManager()); + initializeDweetingPreferences(getPreferenceManager()); } else if(action.equals(DATA_SOURCE_PREFERENCE)) { addPreferencesFromResource(R.xml.data_source_preferences); initializeDataSourcePreferences(getPreferenceManager()); @@ -223,6 +225,8 @@ public void onCreate(Bundle savedInstanceState) { addPreferencesFromResource(R.xml.recording_preferences); ((SettingsActivity)getActivity()).initializeUploadingPreferences( getPreferenceManager()); + ((SettingsActivity)getActivity()).initializeDweetingPreferences( + getPreferenceManager()); } } @@ -286,6 +290,21 @@ protected void initializeUploadingPreferences(PreferenceManager manager) { getString(R.string.uploading_path_key), null)); } + protected void initializeDweetingPreferences(PreferenceManager manager) { + mDweetingPreference = (CheckBoxPreference) manager.findPreference( + getString(R.string.dweeting_checkbox_key)); + Preference dweetingPathPreference = manager.findPreference( + getString(R.string.dweeting_thingname_key)); + dweetingPathPreference.setOnPreferenceChangeListener( + mDweetingPathPreferenceListener); + + SharedPreferences preferences = + PreferenceManager.getDefaultSharedPreferences(this); + updateSummary(dweetingPathPreference, + preferences.getString( + getString(R.string.dweeting_thingname_key), null)); + } + protected void initializeVehicleInterfacePreference(PreferenceManager manager) { mVehicleInterfaceListPreference = (ListPreference) manager.findPreference(getString( @@ -485,6 +504,16 @@ public boolean onPreferenceChange(Preference preference, } }; + private OnPreferenceChangeListener mDweetingPathPreferenceListener = + new OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, + Object newValue) { + String path = (String) newValue; + updateSummary(preference, newValue); + return true; + } + }; + private Preference.OnPreferenceClickListener mTraceFileClickListener = new Preference.OnPreferenceClickListener() { diff --git a/enabler/src/main/java/com/openxc/enabler/preferences/DweetingPreferenceManager.java b/enabler/src/main/java/com/openxc/enabler/preferences/DweetingPreferenceManager.java new file mode 100644 index 000000000..90cb3239c --- /dev/null +++ b/enabler/src/main/java/com/openxc/enabler/preferences/DweetingPreferenceManager.java @@ -0,0 +1,84 @@ +package com.openxc.enabler.preferences; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; + +import com.buglabs.dweetlib.DweetLib; +import com.openxc.sinks.DweetSink; +import com.openxc.sinks.VehicleDataSink; +import com.openxcplatform.enabler.R; + +/** + * Enable or disable sending of vehicle data to dweet.io. + * + * The thingname to send data is read from the shared + * preferences. + */ +public class DweetingPreferenceManager extends VehiclePreferenceManager { + private final static String TAG = "DweetPreferenceManager"; + private VehicleDataSink mDweeter; + + public DweetingPreferenceManager(Context context) { + super(context); + } + + public void close() { + super.close(); + stopDweeting(); + } + + protected PreferenceListener createPreferenceListener() { + return new PreferenceListener() { + private int[] WATCHED_PREFERENCE_KEY_IDS = { + R.string.dweeting_checkbox_key, + R.string.dweeting_thingname_key + }; + + protected int[] getWatchedPreferenceKeyIds() { + return WATCHED_PREFERENCE_KEY_IDS; + } + + public void readStoredPreferences() { + setDweetingStatus(getPreferences().getBoolean(getString( + R.string.dweeting_checkbox_key), false)); + } + }; + } + + private void setDweetingStatus(boolean enabled) { + Log.i(TAG, "Setting dweet to " + enabled); + SharedPreferences.Editor editor = getPreferences().edit(); + String thingname = getPreferenceString(R.string.dweeting_thingname_key); + if (thingname.equals("")) { + thingname = DweetLib.getInstance(getContext()).getRandomThingName(); + editor.putString(getString(R.string.dweeting_thingname_key), thingname); + editor.putString(getString(R.string.dweeting_thingname_default), thingname); + editor.apply(); + } + if(enabled) { + if(mDweeter != null) { + stopDweeting(); + } + + try { + mDweeter = new DweetSink(getContext(), thingname); + } catch(Exception e) { + Log.w(TAG, "Unable to add dweet sink", e); + return; + } + getVehicleManager().addSink(mDweeter); + + } else { + stopDweeting(); + } + } + + private void stopDweeting() { + if(getVehicleManager() != null){ + Log.d(TAG,"removing Dweet sink"); + getVehicleManager().removeSink(mDweeter); + mDweeter = null; + } + } +} diff --git a/enabler/src/main/java/com/openxc/enabler/preferences/PreferenceManagerService.java b/enabler/src/main/java/com/openxc/enabler/preferences/PreferenceManagerService.java index 20c8649c3..f25294948 100644 --- a/enabler/src/main/java/com/openxc/enabler/preferences/PreferenceManagerService.java +++ b/enabler/src/main/java/com/openxc/enabler/preferences/PreferenceManagerService.java @@ -1,9 +1,5 @@ package com.openxc.enabler.preferences; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - import android.app.Service; import android.content.ComponentName; import android.content.Context; @@ -16,6 +12,10 @@ import com.openxc.VehicleManager; import com.openxc.remote.VehicleServiceException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + public class PreferenceManagerService extends Service { private static String TAG = "PreferenceManagerService"; @@ -43,6 +43,7 @@ public void onCreate() { mPreferenceManagers = new ArrayList(); mBluetoothPreferenceManager = new BluetoothPreferenceManager(this); mPreferenceManagers.add(mBluetoothPreferenceManager); + mPreferenceManagers.add(new DweetingPreferenceManager(this)); mPreferenceManagers.add(new FileRecordingPreferenceManager(this)); mPreferenceManagers.add(new GpsOverwritePreferenceManager(this)); mPreferenceManagers.add(new NativeGpsPreferenceManager(this)); diff --git a/enabler/src/main/res/values/strings.xml b/enabler/src/main/res/values/strings.xml index 13de28739..3322949c9 100644 --- a/enabler/src/main/res/values/strings.xml +++ b/enabler/src/main/res/values/strings.xml @@ -62,5 +62,10 @@ VI Version VI Device ID + Send Data to Dweet.io + Enables sending data to Dweet.io cloud messaging service + Thing-name + Set Dweet.io thing-name + diff --git a/enabler/src/main/res/xml/recording_preferences.xml b/enabler/src/main/res/xml/recording_preferences.xml index b884abbe2..3f3932875 100644 --- a/enabler/src/main/res/xml/recording_preferences.xml +++ b/enabler/src/main/res/xml/recording_preferences.xml @@ -27,5 +27,19 @@ android:defaultValue="http://" android:inputType="textUri" /> + + + + diff --git a/library/src/main/assets/adjectives.txt b/library/src/main/assets/adjectives.txt new file mode 100644 index 000000000..44c4c7d11 --- /dev/null +++ b/library/src/main/assets/adjectives.txt @@ -0,0 +1,1133 @@ +aback +abaft +abandoned +abashed +aberrant +abhorrent +abiding +abject +ablaze +able +abnormal +aboard +aboriginal +abortive +abounding +abrasive +abrupt +absent +absorbed +absorbing +abstracted +absurd +abundant +abusive +acceptable +accessible +accidental +accurate +acid +acidic +acoustic +acrid +actually +ad hoc +adamant +adaptable +addicted +adhesive +adjoining +adorable +adventurous +afraid +aggressive +agonizing +agreeable +ahead +ajar +alcoholic +alert +alike +alive +alleged +alluring +aloof +amazing +ambiguous +ambitious +amuck +amused +amusing +ancient +angry +animated +annoyed +annoying +anxious +apathetic +aquatic +aromatic +arrogant +ashamed +aspiring +assorted +astonishing +attractive +auspicious +automatic +available +average +awake +aware +awesome +awful +axiomatic +bad +barbarous +bashful +bawdy +beautiful +befitting +belligerent +beneficial +bent +berserk +best +better +bewildered +big +billowy +bite-sized +bitter +bizarre +black +black-and-white +bloody +blue +blue-eyed +blushing +boiling +boorish +bored +boring +bouncy +boundless +brainy +brash +brave +brawny +breakable +breezy +brief +bright +bright +broad +broken +brown +bumpy +burly +bustling +busy +cagey +calculating +callous +calm +capable +capricious +careful +careless +caring +cautious +ceaseless +certain +changeable +charming +cheap +cheerful +chemical +chief +childlike +chilly +chivalrous +chubby +chunky +clammy +classy +clean +clear +clever +cloistered +cloudy +closed +clumsy +cluttered +coherent +cold +colorful +colossal +combative +comfortable +common +complete +complex +concerned +condemned +confused +conscious +cooing +cool +cooperative +coordinated +courageous +cowardly +crabby +craven +crazy +creepy +crooked +crowded +cruel +cuddly +cultured +cumbersome +curious +curly +curved +curvy +cut +cute +cute +cynical +daffy +daily +damaged +damaging +damp +dangerous +dapper +dark +dashing +dazzling +dead +deadpan +deafening +dear +debonair +decisive +decorous +deep +deeply +defeated +defective +defiant +delicate +delicious +delightful +demonic +delirious +dependent +depressed +deranged +descriptive +deserted +detailed +determined +devilish +didactic +different +difficult +diligent +direful +dirty +disagreeable +disastrous +discreet +disgusted +disgusting +disillusioned +dispensable +distinct +disturbed +divergent +dizzy +domineering +doubtful +drab +draconian +dramatic +dreary +drunk +dry +dull +dusty +dusty +dynamic +dysfunctional +eager +early +earsplitting +earthy +easy +eatable +economic +educated +efficacious +efficient +eight +elastic +elated +elderly +electric +elegant +elfin +elite +embarrassed +eminent +empty +enchanted +enchanting +encouraging +endurable +energetic +enormous +entertaining +enthusiastic +envious +equable +equal +erect +erratic +ethereal +evanescent +evasive +even +excellent +excited +exciting +exclusive +exotic +expensive +extra-large +extra-small +exuberant +exultant +fabulous +faded +faint +fair +faithful +fallacious +false +familiar +famous +fanatical +fancy +fantastic +far +far-flung +fascinated +fast +fat +faulty +fearful +fearless +feeble +feigned +female +fertile +festive +few +fierce +filthy +fine +finicky +first +five +fixed +flagrant +flaky +flashy +flat +flawless +flimsy +flippant +flowery +fluffy +fluttering +foamy +foolish +foregoing +forgetful +fortunate +four +frail +fragile +frantic +free +freezing +frequent +fresh +fretful +friendly +frightened +frightening +full +fumbling +functional +funny +furry +furtive +future +futuristic +fuzzy +gabby +gainful +gamy +gaping +garrulous +gaudy +general +gentle +giant +giddy +gifted +gigantic +glamorous +gleaming +glib +glistening +glorious +glossy +godly +good +goofy +gorgeous +graceful +grandiose +grateful +gratis +gray +greasy +great +greedy +green +grey +grieving +groovy +grotesque +grouchy +grubby +gruesome +grumpy +guarded +guiltless +gullible +gusty +guttural +habitual +half +hallowed +halting +handsome +handsomely +handy +hanging +hapless +happy +hard +hard-to-find +harmonious +harsh +hateful +heady +healthy +heartbreaking +heavenly +heavy +hellish +helpful +helpless +hesitant +hideous +high +highfalutin +high-pitched +hilarious +hissing +historical +holistic +hollow +homeless +homely +honorable +horrible +hospitable +hot +huge +hulking +humdrum +humorous +hungry +hurried +hurt +hushed +husky +hypnotic +hysterical +icky +icy +idiotic +ignorant +ill +illegal +ill-fated +ill-informed +illustrious +imaginary +immense +imminent +impartial +imperfect +impolite +important +imported +impossible +incandescent +incompetent +inconclusive +industrious +incredible +inexpensive +infamous +innate +innocent +inquisitive +insidious +instinctive +intelligent +interesting +internal +invincible +irate +irritating +itchy +jaded +jagged +jazzy +jealous +jittery +jobless +jolly +joyous +judicious +juicy +jumbled +jumpy +juvenile +kaput +keen +kind +kindhearted +kindly +knotty +knowing +knowledgeable +known +labored +lackadaisical +lacking +lame +lamentable +languid +large +last +late +laughable +lavish +lazy +lean +learned +left +legal +lethal +level +lewd +light +like +likeable +limping +literate +little +lively +lively +living +lonely +long +longing +long-term +loose +lopsided +loud +loutish +lovely +loving +low +lowly +lucky +ludicrous +lumpy +lush +luxuriant +lying +lyrical +macabre +macho +maddening +madly +magenta +magical +magnificent +majestic +makeshift +male +malicious +mammoth +maniacal +many +marked +massive +married +marvelous +material +materialistic +mature +mean +measly +meaty +medical +meek +mellow +melodic +melted +merciful +mere +messy +mighty +military +milky +mindless +miniature +minor +miscreant +misty +mixed +moaning +modern +moldy +momentous +motionless +mountainous +muddled +mundane +murky +mushy +mute +mysterious +naive +nappy +narrow +nasty +natural +naughty +nauseating +near +neat +nebulous +necessary +needless +needy +neighborly +nervous +new +next +nice +nifty +nimble +nine +nippy +noiseless +noisy +nonchalant +nondescript +nonstop +normal +nostalgic +nosy +noxious +null +numberless +numerous +nutritious +nutty +oafish +obedient +obeisant +obese +obnoxious +obscene +obsequious +observant +obsolete +obtainable +oceanic +odd +offbeat +old +old-fashioned +omniscient +one +onerous +open +opposite +optimal +orange +ordinary +organic +ossified +outgoing +outrageous +outstanding +oval +overconfident +overjoyed +overrated +overt +overwrought +painful +painstaking +pale +paltry +panicky +panoramic +parallel +parched +parsimonious +past +pastoral +pathetic +peaceful +penitent +perfect +periodic +permissible +perpetual +petite +petite +phobic +physical +picayune +pink +piquant +placid +plain +plant +plastic +plausible +pleasant +plucky +pointless +poised +polite +political +poor +possessive +possible +powerful +precious +premium +present +pretty +previous +pricey +prickly +private +probable +productive +profuse +protective +proud +psychedelic +psychotic +public +puffy +pumped +puny +purple +purring +pushy +puzzled +puzzling +quack +quaint +quarrelsome +questionable +quick +quickest +quiet +quirky +quixotic +quizzical +rabid +racial +ragged +rainy +rambunctious +rampant +rapid +rare +raspy +ratty +ready +real +rebel +receptive +recondite +red +redundant +reflective +regular +relieved +remarkable +reminiscent +repulsive +resolute +resonant +responsible +rhetorical +rich +right +righteous +rightful +rigid +ripe +ritzy +roasted +robust +romantic +roomy +rotten +rough +round +royal +ruddy +rude +rural +rustic +ruthless +sable +sad +safe +salty +same +sassy +satisfying +savory +scandalous +scarce +scared +scary +scattered +scientific +scintillating +scrawny +screeching +second +second-hand +secret +secretive +sedate +seemly +selective +selfish +separate +serious +shaggy +shaky +shallow +sharp +shiny +shivering +shocking +short +shrill +shut +shy +sick +silent +silent +silky +silly +simple +simplistic +sincere +six +skillful +skinny +sleepy +slim +slimy +slippery +sloppy +slow +small +smart +smelly +smiling +smoggy +smooth +sneaky +snobbish +snotty +soft +soggy +solid +somber +sophisticated +sordid +sore +sore +sour +sparkling +special +spectacular +spicy +spiffy +spiky +spiritual +spiteful +splendid +spooky +spotless +spotted +spotty +spurious +squalid +square +squealing +squeamish +staking +stale +standing +statuesque +steadfast +steady +steep +stereotyped +sticky +stiff +stimulating +stingy +stormy +straight +strange +striped +strong +stupendous +stupid +sturdy +subdued +subsequent +substantial +successful +succinct +sudden +sulky +super +superb +superficial +supreme +swanky +sweet +sweltering +swift +symptomatic +synonymous +taboo +tacit +tacky +talented +tall +tame +tan +tangible +tangy +tart +tasteful +tasteless +tasty +tawdry +tearful +tedious +teeny +teeny-tiny +telling +temporary +ten +tender +tense +tense +tenuous +terrible +terrific +tested +testy +thankful +therapeutic +thick +thin +thinkable +third +thirsty +thirsty +thoughtful +thoughtless +threatening +three +thundering +tidy +tight +tightfisted +tiny +tired +tiresome +toothsome +torpid +tough +towering +tranquil +trashy +tremendous +tricky +trite +troubled +truculent +true +truthful +two +typical +ubiquitous +ugliest +ugly +ultra +unable +unaccountable +unadvised +unarmed +unbecoming +unbiased +uncovered +understood +undesirable +unequal +unequaled +uneven +unhealthy +uninterested +unique +unkempt +unknown +unnatural +unruly +unsightly +unsuitable +untidy +unused +unusual +unwieldy +unwritten +upbeat +uppity +upset +uptight +used +useful +useless +utopian +utter +uttermost +vacuous +vagabond +vague +valuable +various +vast +vengeful +venomous +verdant +versed +victorious +vigorous +violent +violet +vivacious +voiceless +volatile +voracious +vulgar +wacky +waggish +waiting +wakeful +wandering +wanting +warlike +warm +wary +wasteful +watery +weak +wealthy +weary +well-groomed +well-made +well-off +well-to-do +wet +whimsical +whispering +white +whole +wholesale +wicked +wide +wide-eyed +wiggly +wild +willing +windy +wiry +wise +wistful +witty +woebegone +womanly +wonderful +wooden +woozy +workable +worried +worthless +wrathful +wretched +wrong +wry +yellow +yielding +young +youthful +yummy +zany +zealous +zesty +zippy +zonked diff --git a/library/src/main/assets/nouns.txt b/library/src/main/assets/nouns.txt new file mode 100644 index 000000000..167b0e109 --- /dev/null +++ b/library/src/main/assets/nouns.txt @@ -0,0 +1,982 @@ +able +able +account +achieve +acoustics +act +action +activity +actor +addition +adjustment +advertisement +advice +aftermath +afternoon +afterthought +agreement +air +airplane +airport +alarm +amount +amusement +anger +angle +animal +answer +ant +ants +apparatus +apparel +apple +apples +appliance +approval +arch +argument +arithmetic +arm +army +art +attack +attempt +attention +attraction +aunt +authority +babies +baby +back +badge +bag +bait +balance +ball +balloon +balls +banana +band +base +baseball +basin +basket +basketball +bat +bath +battle +bead +beam +bean +bear +bears +beast +bed +bedroom +beds +bee +beef +beetle +beggar +beginner +behavior +belief +believe +bell +bells +berry +bike +bikes +bird +birds +birth +birthday +bit +bite +blade +blood +blow +board +boat +boats +body +bomb +bone +book +books +boot +border +bottle +boundary +box +boy +boys +brain +brake +branch +brass +bread +breakfast +breath +brick +bridge +brother +brothers +brush +bubble +bucket +building +bulb +bun +burn +burst +bushes +business +butter +button +cabbage +cable +cactus +cake +cakes +calculator +calendar +camera +camp +can +cannon +canvas +cap +caption +car +card +care +carpenter +carriage +cars +cart +cast +cat +cats +cattle +cause +cave +celery +cellar +cemetery +cent +chain +chair +chairs +chalk +chance +change +channel +cheese +cherries +cherry +chess +chicken +chickens +children +chin +church +circle +clam +class +clock +clocks +cloth +cloud +clouds +clover +club +coach +coal +coast +coat +cobweb +coil +collar +color +comb +comfort +committee +company +comparison +competition +condition +connection +control +cook +copper +copy +cord +cork +corn +cough +country +cover +cow +cows +crack +cracker +crate +crayon +cream +creator +creature +credit +crib +crime +crook +crow +crowd +crown +crush +cry +cub +cup +current +curtain +curve +cushion +dad +daughter +day +death +debt +decision +deer +degree +design +desire +desk +destruction +detail +development +digestion +dime +dinner +dinosaurs +direction +dirt +discovery +discussion +disease +disgust +distance +distribution +division +dock +doctor +dog +dogs +doll +dolls +donkey +door +downtown +drain +drawer +dress +drink +driving +drop +drug +drum +duck +ducks +dust +ear +earth +earthquake +edge +education +effect +egg +eggnog +eggs +elbow +end +engine +error +event +example +exchange +existence +expansion +experience +expert +eye +eyes +face +fact +fairies +fall +family +fan +fang +farm +farmer +father +father +faucet +fear +feast +feather +feeling +feet +fiction +field +fifth +fight +finger +finger +fire +fireman +fish +flag +flame +flavor +flesh +flight +flock +floor +flower +flowers +fly +fog +fold +food +foot +force +fork +form +fowl +frame +friction +friend +friends +frog +frogs +front +fruit +fuel +furniture +alley +game +garden +gate +geese +ghost +giants +giraffe +girl +girls +glass +glove +glue +goat +gold +goldfish +good-bye +goose +government +governor +grade +grain +grandfather +grandmother +grape +grass +grip +ground +group +growth +guide +guitar +gun +hair +haircut +hall +hammer +hand +hands +harbor +harmony +hat +hate +head +health +hearing +heart +heat +help +hen +hill +history +hobbies +hole +holiday +home +honey +hook +hope +horn +horse +horses +hose +hospital +hot +hour +house +houses +humor +hydrant +ice +icicle +idea +impulse +income +increase +industry +ink +insect +instrument +insurance +interest +invention +iron +island +jail +jam +jar +jeans +jelly +jellyfish +jewel +join +joke +journey +judge +juice +jump +kettle +key +kick +kiss +kite +kitten +kittens +kitty +knee +knife +knot +knowledge +laborer +lace +ladybug +lake +lamp +land +language +laugh +lawyer +lead +leaf +learning +leather +leg +legs +letter +letters +lettuce +level +library +lift +light +limit +line +linen +lip +liquid +list +lizards +loaf +lock +locket +look +loss +love +low +lumber +lunch +lunchroom +machine +magic +maid +mailbox +man +manager +map +marble +mark +market +mask +mass +match +meal +measure +meat +meeting +memory +men +metal +mice +middle +milk +mind +mine +minister +mint +minute +mist +mitten +mom +money +monkey +month +moon +morning +mother +motion +mountain +mouth +move +muscle +music +nail +name +nation +neck +need +needle +nerve +nest +net +news +night +noise +north +nose +note +notebook +number +nut +oatmeal +observation +ocean +offer +office +oil +operation +opinion +orange +oranges +order +organization +ornament +oven +owl +owner +page +pail +pain +paint +pan +pancake +paper +parcel +parent +park +part +partner +party +passenger +paste +patch +payment +peace +pear +pen +pencil +person +pest +pet +pets +pickle +picture +pie +pies +pig +pigs +pin +pipe +pizzas +place +plane +planes +plant +plantation +plants +plastic +plate +play +playground +pleasure +plot +plough +pocket +point +poison +police +polish +pollution +popcorn +porter +position +pot +potato +powder +power +price +print +prison +process +produce +profit +property +prose +protest +pull +pump +punishment +purpose +push +quarter +quartz +queen +question +quicksand +quiet +quill +quilt +quince +quiver +rabbit +rabbits +rail +railway +rain +rainstorm +rake +range +rat +rate +ray +reaction +reading +reason +receipt +recess +record +regret +relation +religion +representative +request +respect +rest +reward +rhythm +rice +riddle +rifle +ring +rings +river +road +robin +rock +rod +roll +roof +room +root +rose +route +rub +rule +run +sack +sail +salt +sand +scale +scarecrow +scarf +scene +scent +school +science +scissors +screw +sea +seashore +seat +secretary +seed +selection +self +sense +servant +shade +shake +shame +shape +sheep +sheet +shelf +ship +shirt +shock +shoe +shoes +shop +show +side +sidewalk +sign +silk +silver +sink +sister +sisters +size +skate +skin +skirt +sky +slave +sleep +sleet +slip +slope +smash +smell +smile +smoke +snail +snails +snake +snakes +sneeze +snow +soap +society +sock +soda +sofa +son +song +songs +sort +sound +soup +space +spade +spark +spiders +sponge +spoon +spot +spring +spy +square +squirrel +stage +stamp +star +start +statement +station +steam +steel +stem +step +stew +stick +sticks +stitch +stocking +stomach +stone +stop +store +story +stove +stranger +straw +stream +street +stretch +string +structure +substance +sugar +suggestion +suit +summer +sun +support +surprise +sweater +swim +swing +system +table +tail +talk +tank +taste +tax +teaching +team +teeth +temper +tendency +tent +territory +test +texture +theory +thing +things +thought +thread +thrill +throat +throne +thumb +thunder +ticket +tiger +time +tin +title +toad +toe +toes +tomatoes +tongue +tooth +toothbrush +toothpaste +top +touch +town +toy +toys +trade +trail +train +trains +tramp +transport +tray +treatment +tree +trees +trick +trip +trouble +trousers +truck +trucks +tub +turkey +turn +twig +twist +umbrella +uncle +underwear +unit +use +vacation +value +van +vase +vegetable +veil +vein +verse +vessel +vest +view +visitor +voice +volcano +volleyball +voyage +walk +wall +war +wash +waste +watch +water +wave +waves +wax +way +wealth +weather +week +weight +wheel +whip +whistle +wilderness +wind +window +wine +wing +winter +wire +wish +woman +women +wood +wool +word +work +worm +wound +wren +wrench +wrist +writer +writing +yak +yam +yard +yarn +year +yoke +zebra +zephyr +zinc +zipper +zoo diff --git a/library/src/main/java/com/buglabs/dweetlib/DweetLib.java b/library/src/main/java/com/buglabs/dweetlib/DweetLib.java new file mode 100644 index 000000000..92dfca9c0 --- /dev/null +++ b/library/src/main/java/com/buglabs/dweetlib/DweetLib.java @@ -0,0 +1,342 @@ + +package com.buglabs.dweetlib; + +import android.content.Context; +import android.content.res.AssetManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.AsyncTask; +import android.util.Log; + +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Random; + + +// +// DweetLib Android +// +// Pre-Release version +// +// + edits to replace System.out.println() with Android Logging output +// + adds random thingname generator +// edits by Vishal Kumar on 2015-12-05 +// +// Created by Tim Buick on 2015-06-10. +// Copyright (c) 2015 Bug Labs. All rights reserved. +// + + +public class DweetLib { + + // return codes + public static Integer DWEET_STILL_PENDING=1; + public static Integer DWEET_SUCCESS=0; + public static Integer NO_NETWORK=-1; + public static Integer COULD_NOT_CONNECT_TO_DWEETIO=-2; + public static Integer DWEET_DID_NOT_RETURN_VALID_JSON=-3; + public static Integer DWEET_JSON_FORMAT_UNEXPECTED=-4; + public static Integer DWEET_RESPONSE_IS_FAILED=-5; + public static Integer COULD_NOT_CONNECT_TO_LOCKED_THING=-6; + public static Integer COULD_NOT_GENERATE_JSON_FROM_DATA=-7; + public static Integer CONNECTION_ERROR=-8; + private final static String TAG = "DweetLib"; + + private static DweetLib instance; + + HashMap thingProcess; + HashMap thingProcessUrl; + HashMap thingProcessConnection; + HashMap thingProcessCallback; + HashMap thingProcessCaller; + + private static Context currentCtx; + + static { + instance = new DweetLib(); + } + + private DweetLib() { + thingProcess = new HashMap<>(); + thingProcessUrl = new HashMap<>(); + thingProcessConnection = new HashMap<>(); + thingProcessCallback = new HashMap<>(); + thingProcessCaller = new HashMap<>(); + + + } + + public static DweetLib getInstance(Context ctx) { + currentCtx = ctx; + return DweetLib.instance; + } + + public interface DweetCallback { + void callback(ArrayList ar); + } + + public String sendDweet (JSONObject data,String thing,String key,Object caller,DweetCallback cb,boolean overwrite) { + + final String JSONString = data.toString(); + + final String urlstr = "http://dweet.io/dweet/for/" + thing; + DweetTask dt = (DweetTask) thingProcess.get(urlstr); + + if (!isNetworkingAvailable(currentCtx)) { + Log.w(TAG, "no network error"); + if (caller!=null) { + ArrayList ar = new ArrayList<>(); + ar.add(NO_NETWORK); + cb.callback(ar); + } + DweetTask x = (DweetTask)thingProcessUrl.get(urlstr); + thingProcessUrl.remove(urlstr); + thingProcess.remove(x); + thingProcessConnection.remove(x); + thingProcessCaller.remove(x); + thingProcessCallback.remove(x); + return ""; + } + + if (dt != null) { + Log.w(TAG,"still working"); + if (overwrite) { + Log.w(TAG,"overwriting data"); + String u = (String) thingProcessUrl.get(dt); + thingProcess.remove(u); + HttpURLConnection c = (HttpURLConnection) thingProcessConnection.get(dt); + thingProcessConnection.remove(dt); + thingProcessCallback.remove(dt); + thingProcessCaller.remove(dt); + c.disconnect(); + c = null; + dt.cancel(true); + thingProcessUrl.remove(dt); + dt = null; + } + } + if (dt==null) { + Log.d(TAG,"starting new dt"); + + try { + URL url = new URL(urlstr); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setReadTimeout(5000); // ms + conn.setConnectTimeout(5000); // ms + conn.setRequestProperty("Content-Type", "application/json"); + conn.setRequestMethod("POST"); + conn.setDoInput(true); + + DweetTask x = (DweetTask) new DweetTask().execute(conn,JSONString); + thingProcess.put(urlstr,x); + thingProcessUrl.put(x, urlstr); + thingProcessConnection.put(x, conn); + if (caller!=null) thingProcessCaller.put(x,caller); + if (cb!=null) thingProcessCallback.put(x,cb); + + Log.d(TAG,"conn:"+conn.hashCode()+", task:"+x.hashCode()); + + } catch (Exception e) { + Log.e(TAG,"connection error"); + if (caller!=null) { + ArrayList ar = new ArrayList<>(); + ar.add(CONNECTION_ERROR); + cb.callback(ar); + } + DweetTask x = (DweetTask)thingProcessUrl.get(urlstr); + thingProcessUrl.remove(urlstr); + thingProcess.remove(x); + thingProcessConnection.remove(x); + thingProcessCaller.remove(x); + thingProcessCallback.remove(x); + } + + + } + + + return ""; + + } + + public String getRandomThingName() { + String newThingName = ""; + + AssetManager am = currentCtx.getAssets(); + InputStream is = null; + ArrayList stringArray = new ArrayList(); + BufferedReader br = null; + InputStreamReader inputStreamReader = null; + try { + is = am.open("adjectives.txt"); + } catch (IOException e) { + e.printStackTrace(); + } + if (is!=null) { + String line = null; + try { + inputStreamReader = new InputStreamReader(is); + br = new BufferedReader(inputStreamReader); + while ((line = br.readLine()) != null) { + stringArray.add(line); + } + Random r = new Random(); + int rand1 = r.nextInt(stringArray.size()); + newThingName = newThingName.concat(stringArray.get(rand1)); + } catch (IOException e) { + e.printStackTrace(); + } + } + newThingName = newThingName.concat("-"); + stringArray.clear(); + try { + is = am.open("nouns.txt"); + } catch (IOException e) { + e.printStackTrace(); + } + if (is!=null) { + String line = null; + try { + inputStreamReader = new InputStreamReader(is); + br = new BufferedReader(inputStreamReader); + while ((line = br.readLine()) != null) { + stringArray.add(line); + } + Random r = new Random(); + int rand1 = r.nextInt(stringArray.size()); + newThingName = newThingName.concat(stringArray.get(rand1)); + } catch (IOException e) { + e.printStackTrace(); + } + } + return newThingName; + + } + + + + private class DweetTask extends AsyncTask { + + + @Override + protected void onPostExecute(Integer result) { + super.onPostExecute(result); + Log.d(TAG,this.hashCode() + " onPostExecute:" + result); + HttpURLConnection c = (HttpURLConnection) thingProcessConnection.get(this); + Log.d(TAG,"post conn:" + c.hashCode()); + String urlstr = (String) thingProcessUrl.get(this); + + thingProcess.remove(urlstr); + thingProcessUrl.remove(this); + thingProcessConnection.remove(this); + + if (thingProcessCaller.get(this)!=null) { + DweetCallback dc = (DweetCallback)thingProcessCallback.get(this); + ArrayList ar = new ArrayList<>(); + ar.add(result); + dc.callback(ar); + } + + thingProcessCallback.remove(this); + thingProcessCaller.remove(this); + + } + + @Override + protected Integer doInBackground(Object...params) { + Log.d(TAG,this.hashCode() + " doInBackground"); + InputStream is = null; + String rsp = null; + + HttpURLConnection conn = (HttpURLConnection) params[0]; + String JSONString = (String) params[1]; + try { + OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); + wr.write(JSONString); + wr.flush(); + conn.connect(); + int response = conn.getResponseCode(); + Log.d(TAG,this.hashCode()+" The response is: " + response); + is = conn.getInputStream(); + String contentAsString = convertStreamToString(is); + if (contentAsString.contentEquals("err")) { + return DWEET_DID_NOT_RETURN_VALID_JSON; + } + Log.d(TAG,this.hashCode() + contentAsString); + } catch (IOException e) { + Log.e(TAG,this.hashCode()+" IO Exception"); + return COULD_NOT_CONNECT_TO_DWEETIO; + } + + conn.disconnect(); + return DWEET_SUCCESS; + + } + + + + private String convertStreamToString(InputStream is) { + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder sb = new StringBuilder(); + + String line = null; + try { + while ((line = reader.readLine()) != null) { + sb.append(line).append('\n'); + } + } catch (IOException e) { + e.printStackTrace(); + return "err"; + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + return "err"; + } + } + return sb.toString(); + } + + + } + + + + private static boolean isNetworkingAvailable(Context context) { + if (context == null) { + return false; + } + ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (cm == null) { + return false; + } + NetworkInfo info = cm.getActiveNetworkInfo(); + if (info == null) { + return false; + } + return (info.isAvailable() && info.isConnected()); + } + + + + + +} + + + + + + + + diff --git a/library/src/main/java/com/openxc/sinks/DweetSink.java b/library/src/main/java/com/openxc/sinks/DweetSink.java new file mode 100644 index 000000000..30d5c8f2a --- /dev/null +++ b/library/src/main/java/com/openxc/sinks/DweetSink.java @@ -0,0 +1,157 @@ +package com.openxc.sinks; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import com.buglabs.dweetlib.DweetLib; +import com.openxc.messages.VehicleMessage; +import com.openxc.messages.formatters.JsonFormatter; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +/** + * Sends bundles of all incoming vehicle data to Dweet.io. + * + * + */ +public class DweetSink extends ContextualVehicleDataSink { + private final static String TAG = "DweetSink"; + private final static int UPLOAD_BATCH_SIZE = 25; + private final static int MAXIMUM_QUEUED_RECORDS = 1000; + private final static int HTTP_TIMEOUT = 5000; + + private String mThingName; + private Context mContext; + private BlockingQueue mRecordQueue = + new LinkedBlockingQueue<>(MAXIMUM_QUEUED_RECORDS); + private Lock mQueueLock = new ReentrantLock(); + private Condition mRecordsQueued = mQueueLock.newCondition(); + private DweetThread mDweeter = new DweetThread(); + + /** + * Initialize and start a new DweetSink immediately. + * + * @param thing_name the Thing Name to send Dweets to with the JSON data. + */ + public DweetSink(Context context, String thing_name) { + super(context); + mThingName = thing_name; + mContext = context; + } + + @Override + public void stop() { + mDweeter.done(); + } + + @Override + public void receive(VehicleMessage message) { + mRecordQueue.offer(message); + if(mRecordQueue.size() >= UPLOAD_BATCH_SIZE) { + try { + mQueueLock.lock(); + mRecordsQueued.signal(); + } finally { + mQueueLock.unlock(); + } + } + } + + private static class UploaderException extends DataSinkException { + private static final long serialVersionUID = 7436279598279767619L; + + public UploaderException() { } + + public UploaderException(String message) { + super(message); + } + } + + private class DweetThread extends Thread { + private boolean mRunning = true; + ArrayList records ; + private Handler dweetHandler; + + public DweetThread() { + start(); + dweetHandler = new Handler(Looper.getMainLooper()); + dweetHandler.postDelayed(runnable, 1000); + } + + @Override + public void run() { + while(mRunning) { + try { + records = getRecords(); + } catch(InterruptedException e) { + Log.w(TAG, "Dweeter was interrupted", e); + break; + } + } + } + + public void done() { + mRunning = false; + } + + private ArrayList getRecords() throws InterruptedException { + try { + mQueueLock.lock(); + while(mRecordQueue.isEmpty()) { + // the queue is already thread safe, but we use this lock to get + // a condition variable we can use to signal when a batch has + // been queued. + mRecordsQueued.await(5, TimeUnit.SECONDS); + } + + ArrayList records = new ArrayList<>(); + mRecordQueue.drainTo(records, UPLOAD_BATCH_SIZE); + return records; + } finally { + mQueueLock.unlock(); + } + } + private Runnable runnable = new Runnable() { + @Override + public void run() { + if(mRunning) { + DweetLib.DweetCallback cb = new DweetLib.DweetCallback() { + @Override + public void callback(ArrayList ar) { + Integer result = (Integer) ar.get(0); + } + }; + + JSONObject jsonObj = null; + try { + if(records!=null) { + // add all connected sensor data to JSON object + jsonObj = new JSONObject(); + JSONArray array = new JSONArray(JsonFormatter.serialize(records)); + for (int i = 0; i < array.length(); i++) { + jsonObj.put((String) array.getJSONObject(i).get("name"), array.getJSONObject(i).get("value")); + } + String str = DweetLib.getInstance(mContext).sendDweet(jsonObj, mThingName, "", this, cb, true); + } + } catch (JSONException e) { + Log.e(TAG,"cfg dweet error" + e); + } + // restart the dweet timer + dweetHandler.postDelayed(this, 1000); + } + } + + }; + } +} diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml index 49f2825f4..0e4876896 100644 --- a/library/src/main/res/values/strings.xml +++ b/library/src/main/res/values/strings.xml @@ -9,6 +9,8 @@ recording_output uploading_enabled uploading_target + dweeting_enabled + dweeting_target bluetooth_polling bluetooth_mac network_host From 94fe4e525d2a075692bcbe689be7548e2e34d716 Mon Sep 17 00:00:00 2001 From: Vish Date: Mon, 7 Dec 2015 11:51:48 -0500 Subject: [PATCH 02/15] fixes null pointer issue with first run after installation --- .../openxc/enabler/preferences/DweetingPreferenceManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enabler/src/main/java/com/openxc/enabler/preferences/DweetingPreferenceManager.java b/enabler/src/main/java/com/openxc/enabler/preferences/DweetingPreferenceManager.java index 90cb3239c..3eb754d17 100644 --- a/enabler/src/main/java/com/openxc/enabler/preferences/DweetingPreferenceManager.java +++ b/enabler/src/main/java/com/openxc/enabler/preferences/DweetingPreferenceManager.java @@ -50,7 +50,7 @@ private void setDweetingStatus(boolean enabled) { Log.i(TAG, "Setting dweet to " + enabled); SharedPreferences.Editor editor = getPreferences().edit(); String thingname = getPreferenceString(R.string.dweeting_thingname_key); - if (thingname.equals("")) { + if (thingname == null || thingname.equals("")) { thingname = DweetLib.getInstance(getContext()).getRandomThingName(); editor.putString(getString(R.string.dweeting_thingname_key), thingname); editor.putString(getString(R.string.dweeting_thingname_default), thingname); From 827e94e670459c57f6ddd42bfc0c63868339c0eb Mon Sep 17 00:00:00 2001 From: Vish Date: Tue, 31 May 2016 17:45:53 -0400 Subject: [PATCH 03/15] updated gitignore for android studio 2.0 --- .gitignore | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index c5dbf1db0..89e23f464 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ reference *.releaseBackup release.properties release -assets tokens.xml local.properties @@ -29,7 +28,17 @@ local.properties bin/ gen/ -# Gradle files +# Android Studio / Gradle files +.idea/ +.gradle +/*/local.properties +/*/out +/*/*/production +*.iml +*.iws +*.ipr +*~ +*.swp .gradle/ build/ /*/build/ From a5dbf2df43e5fa125e810474e2c1e888b6887472 Mon Sep 17 00:00:00 2001 From: Vish Date: Tue, 31 May 2016 18:09:46 -0400 Subject: [PATCH 04/15] Integrates Dweet-my-phone functionality; updates project to Android Studio 2.1.1 --- build.gradle | 6 +- enabler/build.gradle | 2 +- .../com/openxc/enabler/SettingsActivity.java | 16 +- .../PhoneSensorSourcePreferenceManager.java | 74 +++++ .../preferences/PreferenceManagerService.java | 1 + enabler/src/main/res/values/strings.xml | 2 + .../main/res/xml/data_source_preferences.xml | 9 + library/src/main/AndroidManifest.xml | 1 + .../main/java/com/openxc/VehicleManager.java | 10 +- .../com/openxc/remote/VehicleService.java | 2 +- .../com/openxc/sources/PhoneSensorSource.java | 290 ++++++++++++++++++ library/src/main/res/values/strings.xml | 2 + 12 files changed, 402 insertions(+), 13 deletions(-) create mode 100644 enabler/src/main/java/com/openxc/enabler/preferences/PhoneSensorSourcePreferenceManager.java create mode 100644 library/src/main/java/com/openxc/sources/PhoneSensorSource.java diff --git a/build.gradle b/build.gradle index 50abcbf35..9018fb37e 100644 --- a/build.gradle +++ b/build.gradle @@ -6,8 +6,8 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.2.3' - classpath 'com.github.dcendents:android-maven-plugin:1.2' + classpath 'com.android.tools.build:gradle:2.1.0' + classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2' classpath 'com.github.triplet.gradle:play-publisher:1.1.2' classpath 'com.bugsnag:bugsnag-android-gradle-plugin:+' @@ -23,7 +23,7 @@ allprojects { ext { compileSdkVersion = 22 - buildToolsVersion = "22.0.1" + buildToolsVersion = "23.0.2" minSdkVersion = 10 targetSdkVersion = 22 diff --git a/enabler/build.gradle b/enabler/build.gradle index fe6feed77..a6536ca04 100644 --- a/enabler/build.gradle +++ b/enabler/build.gradle @@ -78,7 +78,7 @@ android { dependencies { compile project(":library") - compile 'com.android.support:support-v4:19.1.0' + compile 'com.android.support:support-v4:23.4.0' compile 'com.bugsnag:bugsnag-android:3.2.2' androidTestCompile 'junit:junit:4.12' diff --git a/enabler/src/main/java/com/openxc/enabler/SettingsActivity.java b/enabler/src/main/java/com/openxc/enabler/SettingsActivity.java index 90c916406..b83d6a220 100644 --- a/enabler/src/main/java/com/openxc/enabler/SettingsActivity.java +++ b/enabler/src/main/java/com/openxc/enabler/SettingsActivity.java @@ -69,6 +69,9 @@ public class SettingsActivity extends PreferenceActivity { private Preference mAboutVersionPreference; private PreferenceManagerService mPreferenceManager; + private CheckBoxPreference mPhoneSensorPreference; + + private PreferenceCategory mBluetoothPreferences; private PreferenceCategory mNetworkPreferences; private PreferenceCategory mTracePreferences; @@ -270,9 +273,15 @@ protected void initializeTracePreferences(PreferenceManager manager) { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - updateSummary(mTraceFilePreference, - preferences.getString( - getString(R.string.trace_source_file_key), null)); +// updateSummary(mTraceFilePreference, +// preferences.getString( +// getString(R.string.trace_source_file_key), null)); + } + + protected void initializePhoneSensorPreferences(PreferenceManager manager) { + mPhoneSensorPreference = (CheckBoxPreference) manager.findPreference( + getString(R.string.phone_source_polling_checkbox_key)); + } protected void initializeUploadingPreferences(PreferenceManager manager) { @@ -372,6 +381,7 @@ protected void initializeDataSourcePreferences(PreferenceManager manager) { initializeBluetoothPreferences(manager); initializeNetwork(manager); initializeTracePreferences(manager); + initializePhoneSensorPreferences(manager); } protected void initializeBluetoothPreferences(PreferenceManager manager) { diff --git a/enabler/src/main/java/com/openxc/enabler/preferences/PhoneSensorSourcePreferenceManager.java b/enabler/src/main/java/com/openxc/enabler/preferences/PhoneSensorSourcePreferenceManager.java new file mode 100644 index 000000000..2b06f10b5 --- /dev/null +++ b/enabler/src/main/java/com/openxc/enabler/preferences/PhoneSensorSourcePreferenceManager.java @@ -0,0 +1,74 @@ +package com.openxc.enabler.preferences; + +import android.content.Context; +import android.util.Log; + +import com.openxc.remote.VehicleServiceException; +import com.openxc.sources.PhoneSensorSource; +import com.openxcplatform.enabler.R; + +/** + * Created by vish on 5/28/16. + */ + +public class PhoneSensorSourcePreferenceManager extends VehiclePreferenceManager{ + private final static String TAG = "PhoneSensorSourcePreferenceManager"; + + public PhoneSensorSource mPhoneSensorSource; + + public PhoneSensorSourcePreferenceManager(Context context) { + super(context); + } + + public void close() { + super.close(); + stopSensorCapture(); + } + + @Override + protected PreferenceListener createPreferenceListener() { + return new PreferenceListener() { + private int[] WATCHED_PREFERENCE_KEY_IDS = { + R.string.phone_source_polling_checkbox_key + }; + + protected int[] getWatchedPreferenceKeyIds() { + return WATCHED_PREFERENCE_KEY_IDS; + } + + public void readStoredPreferences() { + setPhoneSensorSourceStatus(getPreferences().getBoolean(getString(R.string.phone_source_polling_checkbox_key),false)); + } + }; + } + + private synchronized void setPhoneSensorSourceStatus(boolean enabled) { + Log.i(TAG, "Setting phone source setting to " + enabled); + if(enabled) { + if(mPhoneSensorSource == null) { + stopSensorCapture(); + + try { + mPhoneSensorSource = new PhoneSensorSource( + getContext()); + } catch(Exception e) { + Log.w(TAG, "Unable to start Phone Sensor Source", e); + return; + } + getVehicleManager().addSource(mPhoneSensorSource); + } else { + Log.d(TAG, "Phone Sensor already activated"); + } + } + else { + stopSensorCapture(); + } + } + + private synchronized void stopSensorCapture() { + if(getVehicleManager() != null && mPhoneSensorSource != null){ + getVehicleManager().removeSource(mPhoneSensorSource); + mPhoneSensorSource = null; + } + } +} diff --git a/enabler/src/main/java/com/openxc/enabler/preferences/PreferenceManagerService.java b/enabler/src/main/java/com/openxc/enabler/preferences/PreferenceManagerService.java index f25294948..b06957467 100644 --- a/enabler/src/main/java/com/openxc/enabler/preferences/PreferenceManagerService.java +++ b/enabler/src/main/java/com/openxc/enabler/preferences/PreferenceManagerService.java @@ -50,6 +50,7 @@ public void onCreate() { mPreferenceManagers.add(new UploadingPreferenceManager(this)); mPreferenceManagers.add(new NetworkPreferenceManager(this)); mPreferenceManagers.add(new TraceSourcePreferenceManager(this)); + mPreferenceManagers.add(new PhoneSensorSourcePreferenceManager(this)); mPreferenceManagers.add(new UsbPreferenceManager(this)); mPreferenceManagers.add(new VehicleInterfacePreferenceManager(this)); } diff --git a/enabler/src/main/res/values/strings.xml b/enabler/src/main/res/values/strings.xml index 3322949c9..f0ef14504 100644 --- a/enabler/src/main/res/values/strings.xml +++ b/enabler/src/main/res/values/strings.xml @@ -39,6 +39,8 @@ Network port Trace file playback Select a trace file for playback + Built-In Phone Sensors + Include Data from Phone Sensors About OpenXC Version Version Number diff --git a/enabler/src/main/res/xml/data_source_preferences.xml b/enabler/src/main/res/xml/data_source_preferences.xml index 07b13790f..a195fade1 100644 --- a/enabler/src/main/res/xml/data_source_preferences.xml +++ b/enabler/src/main/res/xml/data_source_preferences.xml @@ -54,4 +54,13 @@ android:key="@string/trace_source_file_key" android:title="@string/trace_source_file_title" /> + + + + diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml index 51d2e4818..830077eb5 100644 --- a/library/src/main/AndroidManifest.xml +++ b/library/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ + diff --git a/library/src/main/java/com/openxc/VehicleManager.java b/library/src/main/java/com/openxc/VehicleManager.java index 19a7bbbcd..93fa9493c 100644 --- a/library/src/main/java/com/openxc/VehicleManager.java +++ b/library/src/main/java/com/openxc/VehicleManager.java @@ -1,10 +1,5 @@ package com.openxc; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - import android.app.Service; import android.content.ComponentName; import android.content.Context; @@ -40,6 +35,11 @@ import com.openxc.sources.RemoteListenerSource; import com.openxc.sources.VehicleDataSource; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + /** * The VehicleManager is an in-process Android service and the primary entry * point into the OpenXC library. diff --git a/library/src/main/java/com/openxc/remote/VehicleService.java b/library/src/main/java/com/openxc/remote/VehicleService.java index 4dea97a56..7656c9a81 100644 --- a/library/src/main/java/com/openxc/remote/VehicleService.java +++ b/library/src/main/java/com/openxc/remote/VehicleService.java @@ -24,7 +24,6 @@ import com.openxc.sources.NativeLocationSource; import com.openxc.sources.VehicleDataSource; import com.openxc.sources.WakeLockManager; - import com.openxcplatform.R; /** @@ -62,6 +61,7 @@ public class VehicleService extends Service implements DataPipeline.Operator { private DataPipeline mPipeline = new DataPipeline(this); private ApplicationSource mApplicationSource = new ApplicationSource(); private VehicleDataSource mNativeLocationSource; + private VehicleDataSource mPhoneSensorSource; private VehicleInterface mVehicleInterface; private RemoteCallbackSink mNotifier = new RemoteCallbackSink(); private WakeLockManager mWakeLocker; diff --git a/library/src/main/java/com/openxc/sources/PhoneSensorSource.java b/library/src/main/java/com/openxc/sources/PhoneSensorSource.java new file mode 100644 index 000000000..afe30e054 --- /dev/null +++ b/library/src/main/java/com/openxc/sources/PhoneSensorSource.java @@ -0,0 +1,290 @@ +package com.openxc.sources; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.media.AudioManager; +import android.os.Build; +import android.os.Bundle; +import android.os.Looper; +import android.util.Log; + +import com.google.common.base.MoreObjects; +import com.openxc.messages.SimpleVehicleMessage; + +import java.util.Arrays; +import java.util.List; + +/** + * Generate location measurements based on native GPS updates. + * + * This source listens for GPS location updates from the built-in Android location + * framework and passes them to the OpenXC vehicle measurement framework as if + * they originated from the vehicle. This source is useful to seamlessly use + * location in an application regardless of it the vehicle has built-in GPS. + * + * The ACCESS_FINE_LOCATION permission is required to use this source. + */ +public class PhoneSensorSource extends ContextualVehicleDataSource + implements SensorEventListener, LocationListener, Runnable { + private final static String TAG = "PhoneSensorSource"; + private final static int DEFAULT_INTERVAL = 5000; + + private Looper mLooper; + + private static LocationManager locationManager; + + + private static SensorManager sensorService; + private Sensor sensor; + private float ax,ay,az; + private float rx,ry,rz; + private float gx,gy,gz; + private float mx,my,mz; + private float light; + private float proximity; + private float humidity; + private float pressure; + private float temperature; + private double altitude, heading, speed; + private Context thecontext; + + String devmodel,devname,osver,headphonesConn; + + public PhoneSensorSource(SourceCallback callback, Context context) { + super(callback, context); + + thecontext = context; + + devmodel = Build.MODEL; + devname = Build.PRODUCT; + osver = Build.VERSION.RELEASE; + + System.out.println("MODEL: "+android.os.Build.MODEL + +"\nDEVICE: "+android.os.Build.DEVICE + +"\nBRAND: "+android.os.Build.BRAND + +"\nDISPLAY: "+android.os.Build.DISPLAY + +"\nBOARD: "+android.os.Build.BOARD + +"\nHOST: "+android.os.Build.HOST + +"\nMANUFACTURER: "+android.os.Build.MANUFACTURER + +"\nPRODUCT: "+android.os.Build.PRODUCT); + + PackageManager PM= context.getPackageManager(); + boolean gyro = PM.hasSystemFeature(PackageManager.FEATURE_SENSOR_GYROSCOPE); + System.out.println("gyro allowed:"+gyro); + sensorService = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + + + List listSensor = sensorService.getSensorList(Sensor.TYPE_ALL); + for(int i=0; i= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + sensorService.registerListener(this, + sensorService.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE), + SensorManager.SENSOR_DELAY_NORMAL); + sensorService.registerListener(this, + sensorService.getDefaultSensor(Sensor.TYPE_RELATIVE_HUMIDITY), + SensorManager.SENSOR_DELAY_NORMAL); + } + + locationManager.requestLocationUpdates( + LocationManager.GPS_PROVIDER, DEFAULT_INTERVAL, 10, this); + + } catch(IllegalArgumentException e) { + Log.w(TAG, "Problem registering Sensor"); + } + + mLooper = Looper.myLooper(); + Looper.loop(); + } + + @Override + public void stop() { + super.stop(); + System.out.println("Phone Sensor service stopped"); + onPipelineDeactivated(); + sensorService.unregisterListener(this); + locationManager.removeUpdates(this); + } + + @Override + public void onSensorChanged(SensorEvent event) { + //System.out.println("Sensor update:"+event.sensor.getName()); + if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { + + float[] accelValues = event.values; + ax = accelValues[0]; + ay = accelValues[1]; + az = accelValues[2]; + + handleMessage(new SimpleVehicleMessage("phone_accelerometer", + Arrays.toString(accelValues))); + + } + if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { + + float[] rotationValues = event.values; + rx = rotationValues[0]; + ry = rotationValues[1]; + rz = rotationValues[2]; + + handleMessage(new SimpleVehicleMessage("phone_rotation", + Arrays.toString(rotationValues))); + } + if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) { + + float[] gyroValues = event.values; + gx = gyroValues[0]; + gy = gyroValues[1]; + gz = gyroValues[2]; + + handleMessage(new SimpleVehicleMessage("phone_gyroscope", Arrays.toString(gyroValues))); + } + if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { + + float[] magnetoValues = event.values; + mx = magnetoValues[0]; + my = magnetoValues[1]; + mz = magnetoValues[2]; + + handleMessage(new SimpleVehicleMessage("phone_magnetometer", Arrays.toString(magnetoValues))); + } + if (event.sensor.getType() == Sensor.TYPE_LIGHT) { + // System.out.println("new light: " + event.values[0]); + light = event.values[0]; + handleMessage(new SimpleVehicleMessage("phone_light_level", light)); + } + if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) { + // System.out.println("new light: " + event.values[0]); + proximity = event.values[0]; + handleMessage(new SimpleVehicleMessage("phone_proximity", proximity)); + } + if (event.sensor.getType() == Sensor.TYPE_PRESSURE) { + // System.out.println("new light: " + event.values[0]); + pressure = event.values[0]; + handleMessage(new SimpleVehicleMessage("phone_atmospheric_pressure", pressure)); + } + if (event.sensor.getType() == Sensor.TYPE_RELATIVE_HUMIDITY) { + // System.out.println("new light: " + event.values[0]); + humidity = event.values[0]; + handleMessage(new SimpleVehicleMessage("phone_relative_humidity", humidity)); + } + if (event.sensor.getType() == Sensor.TYPE_AMBIENT_TEMPERATURE) { + // System.out.println("new light: " + event.values[0]); + temperature = event.values[0]; + handleMessage(new SimpleVehicleMessage("phone_ambient_temperature", temperature)); + } + + AudioManager am1 = (AudioManager)thecontext.getSystemService(Context.AUDIO_SERVICE); + if (am1.isWiredHeadsetOn()) { + headphonesConn="true"; + handleMessage(new SimpleVehicleMessage("phone_headphones_connected", headphonesConn)); + } else { + headphonesConn="false"; + handleMessage(new SimpleVehicleMessage("phone_headphones_connected", headphonesConn)); + } + + + } + + @Override + public void onStatusChanged(String provider, int status, + Bundle extras) {} + + @Override + public void onProviderEnabled(String provider) { } + + @Override + public void onProviderDisabled(String provider) { } + + @Override + public boolean isConnected() { + + return (sensorService != null); + } + + @Override + public void onPipelineActivated() { + Log.i(TAG, "Enabling phone sensor collection"); + new Thread(this).start(); + } + + @Override + public void onPipelineDeactivated() { + Log.i(TAG, "Disabled phone sensor collection"); + if(mLooper != null) { + mLooper.quit(); + } + locationManager.removeUpdates(this); + sensorService.unregisterListener(this); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("updateInterval",DEFAULT_INTERVAL) + .toString(); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int i) { + System.out.println("accuracy changed"); + } + + @Override + public void onLocationChanged(Location location) { + altitude = location.getAltitude(); + heading = location.getBearing(); + speed = location.getSpeed(); + handleMessage(new SimpleVehicleMessage("phone_altitude", altitude)); + handleMessage(new SimpleVehicleMessage("phone_heading", heading)); + handleMessage(new SimpleVehicleMessage("phone_speed", speed)); + } +} diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml index 0e4876896..37e454bde 100644 --- a/library/src/main/res/values/strings.xml +++ b/library/src/main/res/values/strings.xml @@ -16,6 +16,8 @@ network_host network_port playback_trace_file + phone_source_enabled + From eea70fd26c7ecaea5dcebeebb906bab20156c22f Mon Sep 17 00:00:00 2001 From: Eric Marsman Date: Tue, 11 Apr 2017 12:12:20 -0400 Subject: [PATCH 05/15] update copyright/license info. no code changes --- .../src/main/java/com/buglabs/dweetlib/DweetLib.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/library/src/main/java/com/buglabs/dweetlib/DweetLib.java b/library/src/main/java/com/buglabs/dweetlib/DweetLib.java index 92dfca9c0..0ed418025 100644 --- a/library/src/main/java/com/buglabs/dweetlib/DweetLib.java +++ b/library/src/main/java/com/buglabs/dweetlib/DweetLib.java @@ -27,13 +27,10 @@ // // Pre-Release version // -// + edits to replace System.out.println() with Android Logging output -// + adds random thingname generator -// edits by Vishal Kumar on 2015-12-05 -// -// Created by Tim Buick on 2015-06-10. -// Copyright (c) 2015 Bug Labs. All rights reserved. -// +// MIT License +// +// Based off of https://github.com/buglabs/dweet-apps +// with modifications by BugLabs for OpenXC public class DweetLib { From 6e1d6ee7f52b97564e318f6b4cbc0337c994e2f1 Mon Sep 17 00:00:00 2001 From: Eric Marsman Date: Tue, 11 Apr 2017 12:15:28 -0400 Subject: [PATCH 06/15] comments --- CHANGELOG.mkd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.mkd b/CHANGELOG.mkd index 0f6e3ae39..75159dd35 100644 --- a/CHANGELOG.mkd +++ b/CHANGELOG.mkd @@ -6,6 +6,8 @@ * Fix: Evented messages will now show on the dashboard in enabler. * Fix: mKey is stripped from the message before it is written to the tracefile (#253). * Fix: Allow 2-byte PIDs in diagnostic request screen. +* New Feature: Now supports BugLabs Dweet.io formats +* New Feature: Now can include phone sensor data into OpenXC stream. ## v6.1.6 From d510c90e05eec464f410fc266b8ee34b8a56c0bd Mon Sep 17 00:00:00 2001 From: Eric Marsman Date: Tue, 11 Apr 2017 12:33:32 -0400 Subject: [PATCH 07/15] updated build-tools 23.0.2 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2c3c31cc5..78da725e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ android: components: - platform-tools - tools - - build-tools-22.0.1 + - build-tools-23.0.2 - android-22 - extra-android-support - extra-android-m2repository From ce01a609be4b2ba6534574c81eaf235144c59485 Mon Sep 17 00:00:00 2001 From: Eric Marsman Date: Thu, 7 Sep 2017 14:55:54 -0400 Subject: [PATCH 08/15] fix hyperlinks --- README.mkd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.mkd b/README.mkd index eb76890cf..433faf46c 100644 --- a/README.mkd +++ b/README.mkd @@ -14,7 +14,7 @@ application. Visit the [OpenXC][] project page for [installation instructions](http://openxcplatform.com/getting-started/library-installation.html), -[usage details](http://openxcplatform.com/android/api-guide.html) and the +[usage details](http://openxcplatform.com/android/api-guide.html), and the [source code documentation](http://android.openxcplatform.com). ## Building from Android Studio @@ -81,10 +81,10 @@ Please see our [Contribution Documents](https://github.com/openxc/openxc-android ## License -Copyright (c) 2011-2013 Ford Motor Company +Copyright (c) 2011-2017 Ford Motor Company Licensed under the BSD license. -[binding]: http://developer.android.com/guide/topics/fundamentals/bound-services.html#Binding) +[binding]: http://developer.android.com/guide/topics/fundamentals/bound-services.html#Binding [services]: http://developer.android.com/guide/topics/fundamentals/services.html [AIDL]: http://developer.android.com/guide/developing/tools/aidl.html [OpenXC]: http://openxcplatform.com From d3a30a8d56d33fcd75b1105a898b716122392c64 Mon Sep 17 00:00:00 2001 From: Alok Date: Mon, 13 Nov 2017 20:04:49 +0530 Subject: [PATCH 09/15] Commands (#271) * Added a new fragment for the commands tab Added a new array to save the commands * Added Passthrough Request * Added Acceptance Bypass and Payload Filter with Last Request * Added Custom Command Message * UI Changes for Command Screen * Added todo for custom command * Removed custom command tags and variables. Removed unnecessary switch cases * Removed List Fragment * Added Custom Commands and Custom Commands Response --- .../openxc/enabler/OpenXcEnablerActivity.java | 6 +- .../enabler/SendCommandMessageFragment.java | 401 ++++++++++++++++++ .../res/layout/command_request_list_item.xml | 60 +++ .../layout/send_command_message_fragment.xml | 158 +++++++ enabler/src/main/res/values/boolean_array.xml | 7 + .../src/main/res/values/commands_array.xml | 15 + enabler/src/main/res/values/format_array.xml | 7 + enabler/src/main/res/values/strings.xml | 7 + enabler/src/main/res/values/styles.xml | 13 + .../java/com/openxc/messages/Command.java | 140 +++++- .../com/openxc/messages/CustomCommand.java | 92 ++++ .../messages/CustomCommandResponse.java | 114 +++++ .../formatters/CustomCommandSerializer.java | 34 ++ .../messages/formatters/JsonFormatter.java | 28 +- .../com/openxc/sinks/MessageListenerSink.java | 53 ++- 15 files changed, 1084 insertions(+), 51 deletions(-) create mode 100644 enabler/src/main/java/com/openxc/enabler/SendCommandMessageFragment.java create mode 100644 enabler/src/main/res/layout/command_request_list_item.xml create mode 100644 enabler/src/main/res/layout/send_command_message_fragment.xml create mode 100644 enabler/src/main/res/values/boolean_array.xml create mode 100644 enabler/src/main/res/values/commands_array.xml create mode 100644 enabler/src/main/res/values/format_array.xml create mode 100644 library/src/main/java/com/openxc/messages/CustomCommand.java create mode 100644 library/src/main/java/com/openxc/messages/CustomCommandResponse.java create mode 100644 library/src/main/java/com/openxc/messages/formatters/CustomCommandSerializer.java diff --git a/enabler/src/main/java/com/openxc/enabler/OpenXcEnablerActivity.java b/enabler/src/main/java/com/openxc/enabler/OpenXcEnablerActivity.java index 91cc83b18..45e738340 100644 --- a/enabler/src/main/java/com/openxc/enabler/OpenXcEnablerActivity.java +++ b/enabler/src/main/java/com/openxc/enabler/OpenXcEnablerActivity.java @@ -17,9 +17,9 @@ import android.view.MenuItem; import com.bugsnag.android.Bugsnag; -import com.openxcplatform.enabler.BuildConfig; import com.openxc.VehicleManager; import com.openxc.enabler.preferences.PreferenceManagerService; +import com.openxcplatform.enabler.BuildConfig; import com.openxcplatform.enabler.R; /** The OpenXC Enabler app is primarily for convenience, but it also increases @@ -102,7 +102,7 @@ public boolean onCreateOptionsMenu(Menu menu) { public static class EnablerFragmentAdapter extends FragmentPagerAdapter { private static final String[] mTitles = { "Status", "Dashboard", - "CAN", "Diagnostic", "Send CAN" }; + "CAN", "Diagnostic", "Send CAN", "Send Command"}; public EnablerFragmentAdapter(FragmentManager fm) { super(fm); @@ -128,6 +128,8 @@ public Fragment getItem(int position) { return new DiagnosticRequestFragment(); } else if(position == 4) { return new SendCanMessageFragment(); + } else if (position == 5) { + return new SendCommandMessageFragment(); } // For position 0 or anything unrecognized, go to Status diff --git a/enabler/src/main/java/com/openxc/enabler/SendCommandMessageFragment.java b/enabler/src/main/java/com/openxc/enabler/SendCommandMessageFragment.java new file mode 100644 index 000000000..2c58487dd --- /dev/null +++ b/enabler/src/main/java/com/openxc/enabler/SendCommandMessageFragment.java @@ -0,0 +1,401 @@ +package com.openxc.enabler; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.support.v4.app.Fragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.Spinner; +import android.widget.TextView; + +import com.openxc.VehicleManager; +import com.openxc.interfaces.VehicleInterfaceDescriptor; +import com.openxc.messages.Command; +import com.openxc.messages.CustomCommand; +import com.openxc.messages.KeyedMessage; +import com.openxc.messages.VehicleMessage; +import com.openxc.messages.formatters.JsonFormatter; +import com.openxc.remote.VehicleServiceException; +import com.openxc.remote.ViConnectionListener; +import com.openxcplatform.enabler.R; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; + +import static android.view.View.GONE; + +public class SendCommandMessageFragment extends Fragment { + private static String TAG = "SendCommandMsgFragment"; + + public static final int SELECT_COMMAND = 0; + public static final int VERSION_POS = 1; + public static final int DEVICE_ID_POS = 2; + public static final int PLATFORM_POS = 3; + public static final int PASSTHROUGH_CAN_POS = 4; + public static final int ACCEPTANCE_BYPASS_POS = 5; + public static final int PAYLOAD_FORMAT_POS = 6; + public static final int C5_RTC_CONFIG_POS = 7; + public static final int C5_SD_CARD_POS = 8; + public static final int CUSTOM_COMMAND_POS = 9; + + private TextView commandResponseTextView; + private TextView commandRequestTextView; + private View mServiceNotRunningWarningView; + + private VehicleManager mVehicleManager; + + private LinearLayout mBusLayout; + private LinearLayout mEnabledLayout; + private LinearLayout mBypassLayout; + private LinearLayout mFormatLayout; + private LinearLayout mCustomInputLayout; + + private Spinner mBusSpinner; + private Spinner mEnabledSpinner; + private Spinner mBypassSpinner; + private Spinner mFormatSpinner; + private Button mSendButton; + private EditText mCustomInput; + + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, + IBinder service) { + Log.i(TAG, "Bound to VehicleManager"); + mVehicleManager = ((VehicleManager.VehicleBinder) service + ).getService(); + + try { + mVehicleManager.addOnVehicleInterfaceConnectedListener( + mConnectionListener); + } catch (VehicleServiceException e) { + Log.e(TAG, "Unable to register VI connection listener", e); + } + + if (getActivity() == null) { + Log.w(TAG, "Status fragment detached from activity"); + } + + new Thread(new Runnable() { + public void run() { + try { + // It's possible that between starting the thread and + // this running, the manager has gone away. + if (mVehicleManager != null) { + mVehicleManager.waitUntilBound(); + if (getActivity() != null) { + getActivity().runOnUiThread(new Runnable() { + public void run() { + mServiceNotRunningWarningView.setVisibility(GONE); + } + }); + } + } + } catch (VehicleServiceException e) { + Log.w(TAG, "Unable to connect to VehicleService"); + } + + } + }).start(); + + } + + public synchronized void onServiceDisconnected(ComponentName className) { + Log.w(TAG, "VehicleService disconnected unexpectedly"); + mVehicleManager = null; + if (getActivity() != null) { + getActivity().runOnUiThread(new Runnable() { + public void run() { + mServiceNotRunningWarningView.setVisibility(View.VISIBLE); + } + }); + } + } + }; + + private ViConnectionListener mConnectionListener = new ViConnectionListener.Stub() { + public void onConnected(final VehicleInterfaceDescriptor descriptor) { + Log.d(TAG, descriptor + " is now connected"); + } + + public void onDisconnected() { + if (getActivity() != null) { + getActivity().runOnUiThread(new Runnable() { + public void run() { + Log.d(TAG, "VI disconnected"); + } + }); + } + } + }; + + @Override + public void onResume() { + super.onResume(); + if (getActivity() != null) { + getActivity().bindService( + new Intent(getActivity(), VehicleManager.class), + mConnection, Context.BIND_AUTO_CREATE); + } + } + + @Override + public synchronized void onPause() { + super.onPause(); + if (mVehicleManager != null) { + getActivity().unbindService(mConnection); + mVehicleManager = null; + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.send_command_message_fragment, container, false); + + commandResponseTextView = (TextView) v.findViewById(R.id.command_response); + commandRequestTextView = (TextView) v.findViewById(R.id.last_request); + mServiceNotRunningWarningView = v.findViewById(R.id.service_not_running_bar); + mBusLayout = (LinearLayout) v.findViewById(R.id.bus_layout); + mEnabledLayout = (LinearLayout) v.findViewById(R.id.enabled_layout); + mBypassLayout = (LinearLayout) v.findViewById(R.id.bypass_layout); + mFormatLayout = (LinearLayout) v.findViewById(R.id.format_layout); + mCustomInputLayout = (LinearLayout) v.findViewById(R.id.custom_input_layout); + mCustomInput = (EditText) v.findViewById(R.id.customInput); + mBusSpinner = (Spinner) v.findViewById(R.id.bus_spinner); + ArrayAdapter busAdapter = ArrayAdapter.createFromResource( + getActivity(), R.array.buses_array + , android.R.layout.simple_spinner_item); + + busAdapter.setDropDownViewResource( + android.R.layout.simple_spinner_dropdown_item); + mBusSpinner.setAdapter(busAdapter); + + mEnabledSpinner = (Spinner) v.findViewById(R.id.enabled_spinner); + ArrayAdapter enabledAdapter = ArrayAdapter.createFromResource( + getActivity(), R.array.boolean_array + , android.R.layout.simple_spinner_item); + + enabledAdapter.setDropDownViewResource( + android.R.layout.simple_spinner_dropdown_item); + mEnabledSpinner.setAdapter(enabledAdapter); + + mBypassSpinner = (Spinner) v.findViewById(R.id.bypass_spinner); + ArrayAdapter bypassAdapter = ArrayAdapter.createFromResource( + getActivity(), R.array.boolean_array + , android.R.layout.simple_spinner_item); + + bypassAdapter.setDropDownViewResource( + android.R.layout.simple_spinner_dropdown_item); + mBypassSpinner.setAdapter(bypassAdapter); + + mFormatSpinner = (Spinner) v.findViewById(R.id.format_spinner); + ArrayAdapter formatAdapter = ArrayAdapter.createFromResource( + getActivity(), R.array.format_array + , android.R.layout.simple_spinner_item); + + formatAdapter.setDropDownViewResource( + android.R.layout.simple_spinner_dropdown_item); + mFormatSpinner.setAdapter(formatAdapter); + + final Spinner commandSpinner = (Spinner) v.findViewById(R.id.command_spinner); + //set default selection as Select Command + commandSpinner.setSelection(0); + + final ArrayAdapter commandAdapter = ArrayAdapter.createFromResource( + getActivity(), R.array.commands_array + , android.R.layout.simple_spinner_item); + + commandAdapter.setDropDownViewResource( + android.R.layout.simple_spinner_dropdown_item); + commandSpinner.setAdapter(commandAdapter); + + + commandSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView adapterView, View view, int i, long l) { + showSelectedCommandView(i); + } + + @Override + public void onNothingSelected(AdapterView adapterView) { + + } + + }); + + mSendButton = (Button) v.findViewById(R.id.send_request); + mSendButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + int selectedItem = commandSpinner.getSelectedItemPosition(); + sendRequest(selectedItem); + } + }); + + mCustomInput.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View view, boolean hasFocus) { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + if (hasFocus) { + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); + } else { + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } + }); + + getActivity().runOnUiThread(new Runnable() { + public void run() { + mServiceNotRunningWarningView.setVisibility(View.VISIBLE); + } + }); + + return v; + } + + private void sendRequest(int selectedItem) { + if (mVehicleManager != null) { + KeyedMessage request = null; + VehicleMessage response; + int selectedBus; + Boolean enabled, bypass; + String format; + switch (selectedItem) { + case VERSION_POS: + request = new Command(Command.CommandType.VERSION); + break; + + case DEVICE_ID_POS: + request = new Command(Command.CommandType.DEVICE_ID); + break; + + case PLATFORM_POS: + request = new Command(Command.CommandType.PLATFORM); + break; + + case PASSTHROUGH_CAN_POS: + selectedBus = Integer.valueOf(mBusSpinner.getSelectedItem().toString()); + enabled = Boolean.valueOf( + mEnabledSpinner.getSelectedItem().toString()); + request = new Command( + Command.CommandType.PASSTHROUGH, selectedBus, enabled); + break; + + case ACCEPTANCE_BYPASS_POS: + selectedBus = Integer.valueOf(mBusSpinner.getSelectedItem().toString()); + bypass = Boolean.valueOf( + mBypassSpinner.getSelectedItem().toString()); + request = new Command(Command.CommandType.AF_BYPASS, bypass, selectedBus); + break; + + case PAYLOAD_FORMAT_POS: + format = mFormatSpinner.getSelectedItem().toString(); + request = new Command(format, Command.CommandType.PAYLOAD_FORMAT); + break; + + case C5_RTC_CONFIG_POS: + request = new Command(Command.CommandType.RTC_CONFIGURATION, new Date().getTime()); + break; + + case C5_SD_CARD_POS: + request = new Command(Command.CommandType.SD_MOUNT_STATUS); + break; + + case CUSTOM_COMMAND_POS: + String inputString = mCustomInput.getText().toString(); + HashMap inputCommand = getMapFromJson(inputString); + if (inputCommand == null) + mCustomInput.setError(getResources().getString(R.string.input_json_error)); + else + request = new CustomCommand(inputCommand); + break; + default: + break; + } + if (request != null) { + response = mVehicleManager.request(request); + //Update the request TextView + commandRequestTextView.setVisibility(View.VISIBLE); + commandRequestTextView.setText(JsonFormatter.serialize(request)); + + //Update the response TextView + commandResponseTextView.setVisibility(View.VISIBLE); + commandResponseTextView.setText(JsonFormatter.serialize(response)); + } + } + } + + /**** + * This method will return a map of the key value pairs received from JSON. + * If JSON is invalid it will return null. + * @param customJson + * @return HashMap + */ + private HashMap getMapFromJson(String customJson) { + HashMap command = new HashMap<>(); + if (customJson != null) { + try { + JSONObject jsonObject = new JSONObject(customJson); + Iterator iterator = jsonObject.keys(); + while (iterator.hasNext()) { + String key = (String) iterator.next(); + String value = jsonObject.getString(key); + command.put(key, value); + } + return command; + } catch (JSONException exception) { + return null; + } + } else + return null; + } + + private void showSelectedCommandView(int pos) { + commandRequestTextView.setVisibility(GONE); + commandResponseTextView.setVisibility(GONE); + mBusLayout.setVisibility(GONE); + mEnabledLayout.setVisibility(GONE); + mBypassLayout.setVisibility(GONE); + mFormatLayout.setVisibility(GONE); + mCustomInputLayout.setVisibility(GONE); + /*Send button is visible in all views*/ + mSendButton.setVisibility(View.VISIBLE); + switch (pos) { + case SELECT_COMMAND: + mSendButton.setVisibility(GONE); + break; + case PASSTHROUGH_CAN_POS: + mBusLayout.setVisibility(View.VISIBLE); + mEnabledLayout.setVisibility(View.VISIBLE); + break; + case ACCEPTANCE_BYPASS_POS: + mBusLayout.setVisibility(View.VISIBLE); + mBypassLayout.setVisibility(View.VISIBLE); + break; + case PAYLOAD_FORMAT_POS: + mFormatLayout.setVisibility(View.VISIBLE); + break; + case CUSTOM_COMMAND_POS: + mCustomInputLayout.setVisibility(View.VISIBLE); + break; + default: // do nothing + break; + } + } +} diff --git a/enabler/src/main/res/layout/command_request_list_item.xml b/enabler/src/main/res/layout/command_request_list_item.xml new file mode 100644 index 000000000..b0c127c82 --- /dev/null +++ b/enabler/src/main/res/layout/command_request_list_item.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + diff --git a/enabler/src/main/res/layout/send_command_message_fragment.xml b/enabler/src/main/res/layout/send_command_message_fragment.xml new file mode 100644 index 000000000..828862dfb --- /dev/null +++ b/enabler/src/main/res/layout/send_command_message_fragment.xml @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +