package Ġme . h uf man . android aut oid rive . phone ui Ċ Ċ import Ġandroid . content . Context Ċ import Ġandroid . content . Intent Ċ import Ġandroid . graphics . Color Matrix Ċ import Ġandroid . graphics . Color Matrix Color Filter Ċ import Ġandroid . graphics . Type face Ċ import Ġandroid . graphics . drawable . Anim atable 2 Ċ import Ġandroid . graphics . drawable . Animated Vector Drawable Ċ import Ġandroid . graphics . drawable . Drawable Ċ import Ġandroid . os . Bundle Ċ import Ġandroid . os . Handler Ċ import Ġandroid . support . v 4 . app . FragmentManager Ċ import Ġandroid . support . v 4 . app . Notification Manager Compat Ċ import Ġandroid . support . v 7 . app . AppCompatActivity Ċ import Ġandroid . support . v 7 . widget . Linear LayoutManager Ċ import Ġandroid . support . v 7 . widget . RecyclerView Ċ import Ġandroid . support . v 7 . widget . helper . Item Touch Helper Ċ import Ġandroid . view . LayoutInflater Ċ import Ġandroid . view . View Ċ import Ġandroid . view . ViewGroup Ċ import Ġandroid . widget . ImageView Ċ import Ġandroid . widget . LinearLayout Ċ import Ġandroid . widget . TextView Ċ import Ġkotlinx . android . synt hetic . main . activity _ music .* Ċ import Ġkotlinx . android . synt hetic . main . activity _ music . btn Grant Sessions Ċ import Ġkotlinx . android . synt hetic . main . activity _ music . list Music Apps Ċ import Ġkotlinx . android . synt hetic . main . activity _ music . pane Grant Sessions Ċ import Ġme . h uf man . android aut oid rive .* Ċ import Ġme . h uf man . android aut oid rive . music . Music App Info Ċ import Ġme . h uf man . android aut oid rive . music . controllers . Spot ify App Controller Ċ Ċ class ĠMusic Activity Ġ: ĠAppCompatActivity () Ġ{ ĊĊ ĉ val Ġhandler Ġ= ĠHandler () ĊĊ ĉ val Ġdisplayed Apps Ġ= ĠArrayList < Music App Info >() Ċ ĉ val Ġapp Discovery Thread Ġ= ĠApp Discovery Thread ( this ) Ġ{ Ġapp Discovery Ġ-> Ċĉ ĉ handler . post Ġ{ Ċĉĉ ĉ display ed Apps . clear () Ċĉĉ ĉ display ed Apps . addAll ( app Discovery . combined Apps ) Ċĉĉ ĉ list Music Apps . adapter ?. notify DataSet Changed () Ġ// Ġredraw Ġthe Ġapp Ġlist Ċĉ ĉ } Ċ ĉ } Ċ ĉ val Ġapp Settings Ġby Ġlazy Ġ{ ĠMutable AppSettings ( this , Ġhandler ) Ġ} Ċ ĉ val Ġhidden Apps Ġby Ġlazy Ġ{ ĠList Setting ( app Settings , ĠApp Settings . KEYS . HIDDEN _ M US IC _ APPS ) Ġ} ĊĊ ĉ override Ġfun ĠonCreate ( savedInstanceState : ĠBundle ?) Ġ{ Ċĉ ĉ super . onCreate ( savedInstanceState ) Ċĉ ĉ set ContentView ( R . layout . activity _ music ) ĊĊĉ ĉ sw Audio Context . setOn Checked ChangeListener Ġ{ Ġbutton View , Ġis Checked Ġ-> Ċĉĉ ĉ AppSettings . save Setting ( this , ĠApp Settings . KEYS . AUDIO _ FORCE _ CONTEXT , Ġis Checked . toString ()) Ċĉ ĉ } Ċĉ ĉ sw Spot ify Layout . setOn Checked ChangeListener Ġ{ Ġbutton , Ġis Checked Ġ-> Ċĉĉ ĉ AppSettings . save Setting ( this , ĠApp Settings . KEYS . FORCE _ SP OT IFY _ LAYOUT , Ġis Checked . toString ()) Ċĉ ĉ } Ċĉ ĉ btn Grant Sessions . setOnClickListener Ġ{ Ċĉĉ ĉ prompt Notification Permission () Ċĉ ĉ } ĊĊĉ ĉ // Ġbuild Ġlist Ġof Ġdiscovered Ġmusic Ġapps Ċĉ ĉ app Discovery Thread . start () ĊĊĉ ĉ list Music Apps . set Has Fixed Size ( true ) Ċĉ ĉ list Music Apps . layout Manager Ġ= ĠLinearLayoutManager ( this ) Ċĉ ĉ list Music Apps . adapter Ġ= ĠMusic App ListAdapter ( this , Ġhandler , Ġsupport FragmentManager , Ġdisplayed Apps , Ġapp Discovery Thread , Ġhidden Apps ) ĊĊĉ ĉ list Music Apps Refresh . setOn Refresh Listener Ġ{ Ċĉĉ ĉ app Discovery Thread . force Discovery () Ċĉĉ ĉ handler . post Delayed ({ Ċĉĉĉ ĉ list Music Apps Refresh . is Refresh ing Ġ= Ġfalse Ċĉĉ ĉ }, Ġ 2 0 0 0 ) Ċĉ ĉ } ĊĊĉ ĉ val Ġswipe Callback Ġ= Ġobject : ĠItem Touch Helper . Simple Callback ( 0 , ĠItem Touch Helper . LEFT Ġor ĠItem Touch Helper . RIGHT ) Ġ{ Ċĉĉ ĉ override Ġfun Ġon Move ( p 0 : ĠRecyclerView , Ġp 1 : ĠRecyclerView . ViewHolder , Ġp 2 : ĠRecyclerView . ViewHolder ): ĠBoolean Ġ{ Ċĉĉĉ ĉ return Ġfalse Ċĉĉ ĉ } ĊĊĉĉ ĉ override Ġfun Ġon Sw ip ed ( view : ĠRecyclerView . ViewHolder , Ġdirection : ĠInt ) Ġ{ Ċĉĉĉ ĉ val Ġmusic App Info Ġ= Ġ( view Ġas ? ĠMusic App ListAdapter . ViewHolder )?. app Info Ċĉĉĉ ĉ if Ġ( music App Info Ġ!= Ġnull ) Ġ{ Ċĉĉĉĉ ĉ val Ġprevious Ġ= Ġhidden Apps . contains ( music App Info . packageName ) Ċĉĉĉĉ ĉ if Ġ( previous ) Ġ{ Ċĉĉĉĉĉ ĉ hidden Apps . remove ( music App Info . packageName ) Ċĉĉĉĉ ĉ } Ġelse Ġ{ Ċĉĉĉĉĉ ĉ hidden Apps . add ( music App Info . packageName ) Ċĉĉĉĉ ĉ } Ċĉĉĉĉ ĉ list Music Apps . adapter ?. notify Item Changed ( view . adapter Position ) Ċĉĉĉ ĉ } Ċĉĉ ĉ } Ċĉ ĉ } Ċĉ ĉ Item Touch Helper ( swipe Callback ). attach To RecyclerView ( list Music Apps ) Ċ ĉ } ĊĊ ĉ override Ġfun Ġon Resume () Ġ{ Ċĉ ĉ super . on Resume () Ċĉ ĉ redraw () Ċ ĉ } ĊĊ ĉ override Ġfun Ġon Destroy () Ġ{ Ċĉ ĉ super . on Destroy () Ċĉ ĉ app Discovery Thread . stop Discovery () Ċ ĉ } ĊĊ ĉ fun Ġredraw () Ġ{ Ċĉ ĉ val Ġshow Advanced Settings Ġ= ĠApp Settings [ AppSettings . KEYS . SHOW _ ADV ANCED _ SETTINGS ]. to Boolean () Ċĉ ĉ sw Audio Context . visible Ġ= Ġshow Advanced Settings Ġ|| ĠBuild Config . MAN UAL _ AUDIO _ CONTEXT Ċĉ ĉ sw Audio Context . isChecked Ġ= ĠApp Settings [ AppSettings . KEYS . AUDIO _ FORCE _ CONTEXT ]. to Boolean () Ċĉ ĉ sw Spot ify Layout . visible Ġ= Ġshow Advanced Settings Ċĉ ĉ sw Spot ify Layout . isChecked Ġ= ĠApp Settings [ AppSettings . KEYS . FORCE _ SP OT IFY _ LAYOUT ]. to Boolean () Ċĉ ĉ pane Grant Sessions . visibility Ġ= Ġif Ġ( has Notification Permission ()) ĠView . GONE Ġelse ĠView . VISIBLE Ċĉ ĉ app Discovery Thread . discovery () Ċ ĉ } ĊĊ ĉ fun Ġprompt Notification Permission () Ġ{ Ċĉ ĉ startActivity ( Intent (" android . settings . ACTION _ NOTIFICATION _ LIST ENER _ SETTINGS ")) Ċ ĉ } ĊĊ ĉ fun Ġhas Notification Permission (): ĠBoolean Ġ{ Ċĉ ĉ return ĠUI State . notification Listener Connected Ġ&& ĠNotification Manager Compat . get Enabled Listener Packages ( this ). contains ( packageName ) Ċ ĉ } Ċ } Ċ Ċ class ĠMusic App ListAdapter ( val Ġcontext : ĠContext , Ġval Ġhandler : ĠHandler , Ġval Ġsupport FragmentManager : ĠFragment Manager , Ġval Ġcontents : ĠArrayList < Music App Info >, Ġval Ġapp Discovery Thread : ĠApp Discovery Thread , Ġval Ġhidden Apps : ĠSet < String >): ĠRecyclerView . Adapter < Music App ListAdapter . ViewHolder >() Ġ{ ĊĊ ĉ // Ġanimations Ġfor Ġthe Ġmusic Ġsession Ċ ĉ val Ġanimation Loop Callback Ġ= Ġobject : ĠAnim atable 2 . Animation Callback () Ġ{ Ċĉ ĉ override Ġfun Ġon Animation End ( drawable : ĠDrawable ?) Ġ{ Ċĉĉ ĉ handler . post Ġ{ Ġ( drawable Ġas ĠAnimated Vector Drawable ). start () Ġ} Ċĉ ĉ } Ċ ĉ } Ċ ĉ val Ġequal izer Static Ġ= Ġcontext . get Drawable ( R . drawable . ic _ equal izer _ black _ 2 4 dp ) Ċ ĉ val Ġequal izer Animated Ġ= Ġ( context . get Drawable ( R . drawable . ic _ d ancing _ equal izer ) Ġas ĠAnimated Vector Drawable ). apply Ġ{ Ċĉ ĉ this . register Animation Callback ( animation Loop Callback ) Ċ ĉ } Ċ ĉ val Ġgray scale Color Filter Ġ= ĠColor Matrix Color Filter ( Ċĉĉ ĉ Color Matrix (). apply Ġ{ Ġset Sat uration ( 0 . 0 f ) Ġ} Ċ ĉ ) ĊĊ ĉ // Ġhigh Ġlevel Ġhandling Ġto Ġlink Ġa Ġrow ĠView Ġto Ġa Ġspecific ĠMusic App Info Ċ ĉ inner Ġclass ĠViewHolder ( val Ġview : ĠView ): ĠRecyclerView . ViewHolder ( view ), ĠView . OnClickListener Ġ{ Ċĉ ĉ var Ġapp Info : ĠMusic App Info ? Ġ= Ġnull ĊĊĉ ĉ val Ġimg Music App Icon Ġ= Ġview . findViewById < ImageView >( R . id . img Music App Icon ) Ċĉ ĉ val Ġtxt Music AppName Ġ= Ġview . findViewById < TextView >( R . id . txt Music AppName ) Ċĉ ĉ val Ġimg Now Playing Ġ= Ġview . findViewById < ImageView >( R . id . img Now Playing ) Ċĉ ĉ val Ġimg Cont rollable Ġ= Ġview . findViewById < ImageView >( R . id . img Cont rollable ) Ċĉ ĉ val Ġimg Connect able Ġ= Ġview . findViewById < ImageView >( R . id . img Connect able ) Ċĉ ĉ val Ġimg Browse able Ġ= Ġview . findViewById < ImageView >( R . id . img Browse able ) Ċĉ ĉ val Ġimg Search able Ġ= Ġview . findViewById < ImageView >( R . id . img Search able ) Ċĉ ĉ val Ġimg Block Ġ= Ġview . findViewById < ImageView >( R . id . img Block ) Ċĉ ĉ val Ġtxt Music App Features Ġ= Ġview . findViewById < TextView >( R . id . txt Music App Features ) Ċĉ ĉ val Ġpane Music App Features Ġ= Ġview . findViewById < LinearLayout >( R . id . pane Music App Features ) Ċĉ ĉ val Ġtxt Music App Notes Ġ= Ġview . findViewById < TextView >( R . id . txt Music App Notes ) ĊĊĉ ĉ init Ġ{ Ċĉĉ ĉ view . setOnClickListener ( this ) Ċĉ ĉ } ĊĊĉ ĉ fun Ġbind ( app Info : ĠMusic App Info ?) Ġ{ Ċĉĉ ĉ this . app Info Ġ= Ġapp Info Ċĉĉ ĉ if Ġ( app Info Ġ== Ġnull ) Ġ{ Ċĉĉĉ ĉ txt Music AppName . text Ġ= Ġ" Error " Ċĉĉ ĉ } Ġelse Ġ{ Ċĉĉĉ ĉ val Ġicon Ġ= Ġapp Info . icon Ċĉĉĉ ĉ icon . mutate () ĊĊĉĉĉ ĉ if Ġ( hidden Apps . contains ( app Info . packageName )) Ġ{ Ċĉĉĉĉ ĉ img Music App Icon . alpha Ġ= Ġ 0 . 4 f Ċĉĉĉĉ ĉ icon . color Filter Ġ= Ġgray scale Color Filter Ċĉĉĉĉ ĉ txt Music AppName . setTextColor ( txt Music AppName . text Colors . with Alpha ( 1 2 8 )) Ċĉĉĉĉ ĉ txt Music AppName . setType face ( null , ĠType face . ITAL IC ) Ċĉĉĉ ĉ } Ġelse Ġ{ Ċĉĉĉĉ ĉ img Music App Icon . alpha Ġ= Ġ 1 . 0 f Ċĉĉĉĉ ĉ icon . color Filter Ġ= Ġnull Ċĉĉĉĉ ĉ txt Music AppName . setTextColor ( txt Music AppName . text Colors . with Alpha ( 2 5 5 )) Ċĉĉĉĉ ĉ txt Music AppName . setType face ( null , ĠType face . NORMAL ) Ċĉĉĉ ĉ } Ċĉĉĉ ĉ img Music App Icon . setImage Drawable ( icon ) Ċĉĉĉ ĉ txt Music AppName . text Ġ= Ġapp Info . name ĊĊĉĉĉ ĉ if Ġ( app Info . packageName Ġ== Ġapp Discovery Thread . discovery ?. music Sessions ?. get Playing App ()?. packageName ) Ġ{ Ċĉĉĉĉ ĉ img Now Playing . setImage Drawable ( equal izer Animated ) Ċĉĉĉĉ ĉ equal izer Animated . start () Ċĉĉĉĉ ĉ img Now Playing . visibility Ġ= ĠView . VISIBLE Ċĉĉĉ ĉ } Ġelse Ġ{ Ċĉĉĉĉ ĉ img Now Playing . setImage Drawable ( equal izer Static ) Ċĉĉĉĉ ĉ img Now Playing . visibility Ġ= ĠView . GONE Ċĉĉĉ ĉ } Ċĉĉĉ ĉ img Cont rollable . visible Ġ= Ġapp Info . cont rollable Ġ&& Ġ! app Info . connect able Ċĉĉĉ ĉ img Connect able . visible Ġ= Ġapp Info . connect able Ċĉĉĉ ĉ img Browse able . visible Ġ= Ġapp Info . browse able Ċĉĉĉ ĉ img Search able . visible Ġ= Ġapp Info . search able Ġ|| Ġapp Info . play search able Ċĉĉĉ ĉ img Block . visible Ġ= Ġ!( app Info . cont rollable Ġ|| Ġapp Info . connect able ) Ċĉĉĉ ĉ val Ġfeatures Ġ= ĠlistOf NotNull ( Ċĉĉĉĉĉ ĉ if Ġ( app Info . cont rollable Ġ&& Ġ! app Info . connect able ) Ġcontext . getString ( R . string . music App Cont rollable ) Ġelse Ġnull , Ċĉĉĉĉĉ ĉ if Ġ( app Info . connect able ) Ġcontext . getString ( R . string . music App Connect able ) Ġelse Ġnull , Ċĉĉĉĉĉ ĉ if Ġ( app Info . browse able ) Ġcontext . getString ( R . string . music App Browse able ) Ġelse Ġnull , Ċĉĉĉĉĉ ĉ if Ġ( app Info . search able Ġ|| Ġapp Info . play search able ) Ġcontext . getString ( R . string . music App Search able ) Ġelse Ġnull , Ċĉĉĉĉĉ ĉ if Ġ( app Info . cont rollable Ġ|| Ġapp Info . connect able ) Ġnull Ġelse Ġcontext . getString ( R . string . music App Unavailable ), Ċĉĉĉĉĉ ĉ if Ġ( hidden Apps . contains ( app Info . packageName )) Ġcontext . getString ( R . string . music App Hidden ) Ġelse Ġnull Ċĉĉĉ ĉ ). join ToString (", Ġ") Ċĉĉĉ ĉ txt Music App Features . text Ġ= Ġfeatures Ċĉĉĉ ĉ pane Music App Features . setOnClickListener Ġ{ Ċĉĉĉĉ ĉ val Ġtxt Features Ġ= Ġtxt Music App Features Ċĉĉĉĉ ĉ txt Features . visible Ġ= Ġ! txt Features . visible Ċĉĉĉ ĉ } ĊĊĉĉĉ ĉ // Ġshow Ġapp - specific Ġnotes Ċĉĉĉ ĉ if Ġ( app Info . packageName Ġ== Ġ" com . spotify . music " Ġ&& Ġapp Info . pro bed Ġ&& Ġ! app Info . connect able ) Ġ{ Ċĉĉĉĉ ĉ if Ġ( Spot ify App Controller . has Support ( context )) Ġ{ Ċĉĉĉĉĉ ĉ // Ġprompt Ġthe Ġuser Ġto Ġclick Ġagain Ġto Ġshow Ġthe ĠSpotify Ġauth Ġdialog Ċĉĉĉĉĉ ĉ txt Music App Notes . text Ġ= Ġcontext . getString ( R . string . music App Notes _ un authorized Spot ify ) Ċĉĉĉĉĉ ĉ txt Music App Notes . visible Ġ= Ġfalse Ċĉĉĉĉĉ ĉ txt Music App Notes . setOnClickListener ( null ) Ċĉĉĉĉ ĉ } Ġelse Ġ{ Ċĉĉĉĉĉ ĉ // Ġshow Ġa Ġnote Ġto Ġdown grade ĠSpotify Ċĉĉĉĉĉ ĉ txt Music App Notes . text Ġ= Ġcontext . getString ( R . string . music App Notes _ old Spot ify ) Ċĉĉĉĉĉ ĉ txt Music App Notes . visible Ġ= Ġtrue Ċĉĉĉĉĉ ĉ txt Music App Notes . setOnClickListener Ġ{ Ċĉĉĉĉĉĉ ĉ Spot ify Down grade Dialog (). show ( support FragmentManager , Ġ" notes ") Ċĉĉĉĉĉ ĉ } Ċĉĉĉĉ ĉ } Ċĉĉĉĉ ĉ txt Music App Notes . visible Ġ= Ġtrue Ċĉĉĉ ĉ } Ġelse Ġ{ Ċĉĉĉĉ ĉ txt Music App Notes . visible Ġ= Ġfalse Ċĉĉĉĉ ĉ txt Music App Notes . setOnClickListener ( null ) Ċĉĉĉ ĉ } Ċĉĉ ĉ } Ċĉ ĉ } ĊĊĉ ĉ override Ġfun ĠonClick ( item : ĠView ?) Ġ{ Ċĉĉ ĉ if Ġ( this . app Info Ġ!= Ġnull ) Ġ{ Ċĉĉĉ ĉ UIState . selected Music App Ġ= Ġapp Info Ċĉĉĉ ĉ val Ġintent Ġ= ĠIntent ( context , ĠMusic Player Activity :: class . java ) Ċĉĉĉ ĉ context . startActivity ( intent ) Ċĉĉ ĉ } Ċĉ ĉ } Ċ ĉ } ĊĊ ĉ override Ġfun ĠonCreate ViewHolder ( parent : ĠViewGroup , Ġview Type : ĠInt ): ĠViewHolder Ġ{ Ċĉ ĉ val Ġlayout Ġ= ĠLayoutInflater . from ( context ). inflate ( R . layout . music app _ list item , Ġparent , false ) Ċĉ ĉ return ĠViewHolder ( layout ) Ċ ĉ } ĊĊ ĉ override Ġfun ĠgetItem Count (): ĠInt Ġ{ Ċĉ ĉ return Ġcontents . size Ċ ĉ } ĊĊ ĉ override Ġfun Ġon Bind ViewHolder ( holder : ĠViewHolder , Ġposition : ĠInt ) Ġ{ Ċĉ ĉ val Ġapp Info Ġ= Ġcontents . get OrNull ( position ) Ċĉ ĉ holder . bind ( app Info ) Ċ ĉ } Ċ }