/* ĠCopyright Ġ 2 0 2 0 ĠB rad en ĠFar mer Ċ Ġ* Ċ Ġ* ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ Ġ* Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ Ġ* ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ Ġ* Ċ Ġ* ĠĠĠĠ Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ Ġ* Ċ Ġ* ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ Ġ* Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ Ġ* ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ Ġ* ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ Ġ* Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ġ*/ Ċ Ċ package Ġcom . far mer bb . app notifier Ċ Ċ import Ġandroid . app . Notification Manager Ċ import Ġandroid . app . Pending Intent Ċ import Ġandroid . content . Context Ċ import Ġandroid . content . Intent Ċ import Ġandroid . content . SharedPreferences Ċ import Ġandroid . content . pm . Application Info Ċ import Ġandroid . graphics . Bitmap Ċ import Ġandroid . graphics . Canvas Ċ import Ġandroid . graphics . drawable . Bitmap Drawable Ċ import Ġandroidx . core . app . Notification Compat Ċ import Ġandroidx . core . content . Context Compat Ċ import Ġcom . far mer bb . app notifier . models . App Update Info Ċ import Ġcom . far mer bb . app notifier . re ceiv ers . Install Notification Clicked Receiver Ċ import Ġcom . far mer bb . app notifier . re ceiv ers . Install Notification Dis missed Receiver Ċ import Ġcom . far mer bb . app notifier . re ceiv ers . Update Notification Clicked Receiver Ċ import Ġcom . far mer bb . app notifier . re ceiv ers . Update Notification Dis missed Receiver Ċ import Ġcom . far mer bb . app notifier . room . App Update DAO Ċ import Ġkotlinx . coroutines . Global Scope Ċ import Ġkotlinx . coroutines . launch Ċ import Ġjava . util .* Ċ import Ġjavax . inject . Inject Ċ import Ġjavax . inject . Singleton Ċ import Ġkotlin . math . max Ċ import Ġkotlin . math . min Ċ Ċ @ Singleton Ġclass ĠNotification Controller Ġ@ Inject Ġconstructor ( ĊĠĠĠ Ġprivate Ġval Ġcontext : ĠContext , ĊĠĠĠ Ġprivate Ġval Ġpref : ĠSharedPreferences , ĊĠĠĠ Ġprivate Ġval Ġdao : ĠApp Update DAO , ĊĠĠĠ Ġprivate Ġval Ġmanager : ĠNotification Manager Ċ ) Ġ{ ĊĊĠĠĠ Ġfun Ġhandle App Update Notification ( app Info : ĠApplication Info ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif (! pref . getBoolean (" notify _ updates ", Ġtrue ) Ġ|| Ġ! verify Prefs ( app Info . packageName )) Ġreturn ĊĊĠĠĠĠĠĠĠ Ġval Ġinfo Ġ= ĠApp Update Info ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠpackageName Ġ= Ġapp Info . packageName , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlabel Ġ= Ġapp Info . load Label ( context . package Manager ). toString (), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠupdatedAt Ġ= ĠDate (), ĊĠĠĠĠĠĠĠĠĠĠĠ Ġis Install Ġ= Ġfalse ĊĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ ĠGlobal Scope . launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlist : ĠList < App Update Info > ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġdao . apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelete Update ( info . packageName ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlist Ġ= ĠgetAll Updates (). plus ( info ). reversed () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinsert ( info ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġbuild App Update Notification ( list . map Ġ{ Ġit . label Ġ}, Ġlazy Ġ{ Ġget Icon ( app Info ) Ġ}) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġbuild App Update Notification ( list : ĠList < String >, Ġicon : ĠLazy < Bitmap >) Ġ{ ĊĠĠĠĠĠĠĠ Ġif ( list . isEmpty ()) Ġreturn ĊĊĠĠĠĠĠĠĠ Ġval Ġheader : ĠString ĊĠĠĠĠĠĠĠ Ġval Ġcontent : ĠString ĊĊĠĠĠĠĠĠĠ Ġcontext . resources . apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġheader Ġ= Ġget Quantity String ( R . plurals . apps _ updated _ header , Ġlist . size , Ġlist . size ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsub List Ġ= Ġlist . sub List ( 0 , Ġmin ( 4 , Ġlist . size )). to Mutable List (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif ( list . size Ġ>= Ġ 5 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnew Size Ġ= Ġlist . size Ġ- Ġ 4 ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġadd ( get Quantity String ( R . plurals . apps _ updated _ footer , Ġnew Size , Ġnew Size )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġname Ġ= Ġ" apps _ updated _${ if ( list . size Ġ< Ġ 5 ) Ġlist . size . toString () Ġelse Ġ" other "} " ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġid Ġ= Ġget Identifier ( name , Ġ" string ", ĠBuild Config . APPLICATION _ ID ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontent Ġ= ĠgetString ( id , Ġ* sub List . to Typed Array ()) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġchannel Id Ġ= Ġ" app _ updates " ĊĠĠĠĠĠĠĠ Ġcontext . create Notification Channel ( channelId ) ĊĊĠĠĠĠĠĠĠ Ġval Ġcontent Intent Ġ= ĠIntent ( context , ĠUpdate Notification Clicked Receiver :: class . java ). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġset Package ( Build Config . APPLICATION _ ID ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġdelete Intent Ġ= ĠIntent ( context , ĠUpdate Notification Dis missed Receiver :: class . java ). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġset Package ( Build Config . APPLICATION _ ID ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġpending Content Intent Ġ= ĠPending Intent . get Broadcast ( context , Ġ 0 , Ġcontent Intent , ĠFLAGS ) ĊĠĠĠĠĠĠĠ Ġval Ġpending Delete Intent Ġ= ĠPending Intent . get Broadcast ( context , Ġ 0 , Ġdelete Intent , ĠFLAGS ) ĊĊĠĠĠĠĠĠĠ Ġval Ġis Enhanced Ġ= Ġpref . getString (" notification _ text _ style ", Ġ" original ") Ġ== Ġ" en hanced " ĊĊĠĠĠĠĠĠĠ Ġval Ġbuilder Ġ= ĠNotification Compat . Builder ( context , Ġchannel Id ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Small Icon ( R . drawable . app _ updated ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setContent Title ( header ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setContent Text ( content ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setContent Intent ( pending Content Intent ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setStyle ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif ( is Enhanced ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠNotification Compat . Big TextStyle (). big Text ( list . join ToString ( separator Ġ= Ġ"\ n ")) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠNotification Compat . Big TextStyle () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setColor ( Context Compat . getColor ( context , ĠR . color . color Primary )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setAuto Cancel ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Delete Intent ( pending Delete Intent ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Priority ( Notification Compat . PRIORITY _ DEFAULT ) ĊĊĠĠĠĠĠĠĠ Ġif ( is Enhanced ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġbuilder . set Large Icon ( icon . value ) ĊĊĠĠĠĠĠĠĠ Ġmanager . notify ( APP _ UPDATE _ ID , Ġbuilder . build ()) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġhandle App Install Notification ( app Info : ĠApplication Info ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif (! pref . getBoolean (" notify _ install s ", Ġtrue ) Ġ|| Ġ! verify Prefs ( app Info . packageName )) Ġreturn ĊĊĠĠĠĠĠĠĠ Ġval Ġinfo Ġ= ĠApp Update Info ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠpackageName Ġ= Ġapp Info . packageName , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlabel Ġ= Ġapp Info . load Label ( context . package Manager ). toString (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠupdatedAt Ġ= ĠDate (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis Install Ġ= Ġtrue ĊĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ ĠGlobal Scope . launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdao . apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelete Install ( info . packageName ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinsert ( info ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġbuild App Install Notification ( info . packageName , Ġinfo . label , Ġget Icon ( app Info )) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġbuild App Install Notification ( packageName : ĠString , Ġlabel : ĠString , Ġicon : ĠBitmap ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġchannel Id Ġ= Ġ" app _ install s " ĊĠĠĠĠĠĠĠ Ġcontext . create Notification Channel ( channelId ) ĊĊĠĠĠĠĠĠĠ Ġval Ġcode Ġ= ĠpackageName . hashCode () ĊĊĠĠĠĠĠĠĠ Ġval Ġcontent Intent Ġ= ĠIntent ( context , ĠInstall Notification Clicked Receiver :: class . java ). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġset Package ( Build Config . APPLICATION _ ID ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġput Extra ( PACKAGE _ NAME , ĠpackageName ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġdelete Intent Ġ= ĠIntent ( context , ĠInstall Notification Dis missed Receiver :: class . java ). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġset Package ( Build Config . APPLICATION _ ID ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġput Extra ( PACKAGE _ NAME , ĠpackageName ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġpending Content Intent Ġ= ĠPending Intent . get Broadcast ( context , Ġcode , Ġcontent Intent , ĠFLAGS ) ĊĠĠĠĠĠĠĠ Ġval Ġpending Delete Intent Ġ= ĠPending Intent . get Broadcast ( context , Ġcode , Ġdelete Intent , ĠFLAGS ) ĊĊĠĠĠĠĠĠĠ Ġval Ġbuilder Ġ= ĠNotification Compat . Builder ( context , Ġchannel Id ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Small Icon ( R . drawable . app _ updated ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setContent Title ( label ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setContent Text ( context . getString ( R . string . successfully _ installed )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setContent Intent ( pending Content Intent ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setStyle ( Notification Compat . Big TextStyle ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Large Icon ( icon ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setColor ( Context Compat . getColor ( context , ĠR . color . color Primary )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setAuto Cancel ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Delete Intent ( pending Delete Intent ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Group ( APP _ INSTALL _ GROUP ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Priority ( Notification Compat . PRIORITY _ LOW ) ĊĊĠĠĠĠĠĠĠ Ġval Ġgroup Builder Ġ= ĠNotification Compat . Builder ( context , Ġchannel Id ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Small Icon ( R . drawable . app _ updated ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Group ( APP _ INSTALL _ GROUP ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Group Summary ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setAuto Cancel ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setStyle ( Notification Compat . Big TextStyle ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Priority ( Notification Compat . PRIORITY _ LOW ) ĊĊĠĠĠĠĠĠĠ Ġmanager . apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnotify ( APP _ INSTALL _ ID , Ġgroup Builder . build ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnotify ( code , Ġbuilder . build ()) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġcancel App Install Notification ( packageName : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ Ġmanager . cancel ( packageName . hashCode ()) ĊĊĠĠĠĠĠĠĠ ĠGlobal Scope . launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdao . delete Install ( packageName ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif ( dao . getAll Install s (). isEmpty ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmanager . cancel ( APP _ INSTALL _ ID ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġverify Prefs ( packageName : ĠString ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġfrom Play Store Ġ= Ġcontext . package Manager . get Installer PackageName ( packageName ) Ġ== ĠP LAY _ STORE _ PACKAGE ĊĠĠĠĠĠĠĠ Ġif ( pref . getBoolean (" notify _ play _ store ", Ġtrue ) Ġ&& Ġfrom Play Store ) Ġreturn Ġtrue ĊĠĠĠĠĠĠĠ Ġif ( pref . getBoolean (" notify _ other _ sources ", Ġfalse ) Ġ&& Ġ! from Play Store ) Ġreturn Ġtrue ĊĊĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġget Icon ( app Info : ĠApplication Info ): ĠBitmap Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġicon Ġ= Ġcontext . package Manager . getApplication Icon ( app Info ) ĊĠĠĠĠĠĠĠ Ġreturn Ġif ( icon Ġ! is ĠBitmap Drawable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġwidth Ġ= Ġmax ( icon . intrinsic Width , Ġ 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġheight Ġ= Ġmax ( icon . intrinsic Height , Ġ 1 ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbitmap Ġ= ĠBitmap . create Bitmap ( width , Ġheight , ĠBitmap . Config . ARGB _ 8 8 8 8 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcanvas Ġ= ĠCanvas ( bitmap ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġicon . setBounds ( 0 , Ġ 0 , Ġcanvas . width , Ġcanvas . height ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġicon . draw ( canvas ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠBitmap Drawable ( context . resources , Ġbitmap ). bitmap ĊĠĠĠĠĠĠĠ Ġ} Ġelse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġicon . bitmap ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġreplay App Updates () Ġ{ ĊĠĠĠĠĠĠĠ Ġif (! pref . getBoolean (" notify _ updates ", Ġtrue )) Ġreturn ĊĊĠĠĠĠĠĠĠ ĠGlobal Scope . launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġupdates Ġ= Ġdao . getAll Updates (). reversed () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . getApplication Info S af ely ( updates . first (). packageName , Ġdao )?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbuild App Update Notification ( updates . map Ġ{ Ġit . label Ġ}, Ġlazy Ġ{ Ġget Icon ( it ) Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġreplay App Install s () Ġ{ ĊĠĠĠĠĠĠĠ Ġif (! pref . getBoolean (" notify _ install s ", Ġtrue )) Ġreturn ĊĊĠĠĠĠĠĠĠ ĠGlobal Scope . launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfor ( install Ġin Ġdao . getAll Install s ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . getApplication Info S af ely ( install . packageName , Ġdao )?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbuild App Install Notification ( install . packageName , Ġinstall . label , Ġget Icon ( it )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ }