Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
com.ccwangluo.accelerator
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
sheteng
com.ccwangluo.accelerator
Commits
8e17e4fb
Commit
8e17e4fb
authored
Dec 01, 2020
by
Max Lv
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Clean up and bump version
parent
36576a61
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
9 additions
and
367 deletions
+9
-367
buildSrc/src/main/kotlin/Helpers.kt
buildSrc/src/main/kotlin/Helpers.kt
+2
-2
core/build.gradle.kts
core/build.gradle.kts
+3
-4
core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt
.../src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt
+0
-33
core/src/main/java/com/github/shadowsocks/bg/RemoteConfig.kt
core/src/main/java/com/github/shadowsocks/bg/RemoteConfig.kt
+0
-51
core/src/main/java/com/github/shadowsocks/database/Profile.kt
.../src/main/java/com/github/shadowsocks/database/Profile.kt
+1
-1
mobile/build.gradle.kts
mobile/build.gradle.kts
+2
-3
mobile/src/main/java/com/github/shadowsocks/AdsManager.kt
mobile/src/main/java/com/github/shadowsocks/AdsManager.kt
+0
-41
mobile/src/main/java/com/github/shadowsocks/ProfilesFragment.kt
.../src/main/java/com/github/shadowsocks/ProfilesFragment.kt
+0
-120
mobile/src/main/res/layout/ad_unified.xml
mobile/src/main/res/layout/ad_unified.xml
+0
-105
mobile/src/main/res/layout/layout_profile.xml
mobile/src/main/res/layout/layout_profile.xml
+0
-6
repositories.gradle.kts
repositories.gradle.kts
+1
-1
No files found.
buildSrc/src/main/kotlin/Helpers.kt
View file @
8e17e4fb
...
...
@@ -56,8 +56,8 @@ fun Project.setupCore() {
setupCommon
()
android
.
apply
{
defaultConfig
{
versionCode
=
5010
4
50
versionName
=
"5.1.
4
-nightly"
versionCode
=
5010
5
50
versionName
=
"5.1.
5
-nightly"
}
compileOptions
.
isCoreLibraryDesugaringEnabled
=
true
lintOptions
{
...
...
core/build.gradle.kts
View file @
8e17e4fb
...
...
@@ -73,7 +73,7 @@ dependencies {
api
(
project
(
":plugin"
))
api
(
"androidx.appcompat:appcompat:1.2.0"
)
api
(
"androidx.core:core-ktx:1.
4.0-alpha01
"
)
api
(
"androidx.core:core-ktx:1.
5.0-alpha05
"
)
api
(
"androidx.fragment:fragment-ktx:1.3.0-beta01"
)
api
(
"androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion"
)
...
...
@@ -84,9 +84,8 @@ dependencies {
api
(
"androidx.work:work-gcm:$workVersion"
)
api
(
"com.google.android.gms:play-services-oss-licenses:17.0.0"
)
api
(
"com.google.code.gson:gson:2.8.6"
)
api
(
"com.google.firebase:firebase-analytics-ktx:17.5.0"
)
api
(
"com.google.firebase:firebase-config-ktx:19.2.0"
)
api
(
"com.google.firebase:firebase-crashlytics:17.2.2"
)
api
(
"com.google.firebase:firebase-analytics-ktx:18.0.0"
)
api
(
"com.google.firebase:firebase-crashlytics:17.3.0"
)
api
(
"com.jakewharton.timber:timber:4.7.1"
)
api
(
"dnsjava:dnsjava:3.3.0"
)
api
(
"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
)
...
...
core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt
View file @
8e17e4fb
...
...
@@ -32,7 +32,6 @@ import com.github.shadowsocks.preference.DataStore
import
com.github.shadowsocks.utils.parseNumericAddress
import
com.github.shadowsocks.utils.signaturesCompat
import
com.github.shadowsocks.utils.useCancellable
import
com.google.firebase.remoteconfig.ktx.get
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.withContext
...
...
@@ -52,37 +51,6 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
private
var
scheduleConfigUpdate
=
false
suspend
fun
init
(
service
:
BaseService
.
Interface
)
{
if
(
profile
.
isSponsored
)
{
scheduleConfigUpdate
=
true
val
mdg
=
MessageDigest
.
getInstance
(
"SHA-1"
)
mdg
.
update
(
Core
.
packageInfo
.
signaturesCompat
.
first
().
toByteArray
())
val
(
config
,
success
)
=
RemoteConfig
.
fetch
()
scheduleConfigUpdate
=
!
success
val
conn
=
withContext
(
Dispatchers
.
IO
)
{
// Network.openConnection might use networking, see https://issuetracker.google.com/issues/135242093
service
.
openConnection
(
URL
(
config
[
"proxy_url"
].
asString
()))
as
HttpURLConnection
}
conn
.
requestMethod
=
"POST"
conn
.
doOutput
=
true
val
proxies
=
conn
.
useCancellable
{
try
{
outputStream
.
bufferedWriter
().
use
{
it
.
write
(
"sig="
+
Base64
.
encodeToString
(
mdg
.
digest
(),
Base64
.
DEFAULT
))
}
inputStream
.
bufferedReader
().
readText
()
}
catch
(
e
:
IOException
)
{
throw
BaseService
.
ExpectedExceptionWrapper
(
e
)
}
}.
split
(
'|'
).
toMutableList
()
proxies
.
shuffle
()
val
proxy
=
proxies
.
first
().
split
(
':'
)
profile
.
host
=
proxy
[
0
].
trim
()
profile
.
remotePort
=
proxy
[
1
].
trim
().
toInt
()
profile
.
password
=
proxy
[
2
].
trim
()
profile
.
method
=
proxy
[
3
].
trim
()
}
// it's hard to resolve DNS on a specific interface so we'll do it here
if
(
profile
.
host
.
parseNumericAddress
()
==
null
)
{
profile
.
host
=
try
{
...
...
@@ -139,7 +107,6 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
fun
scheduleUpdate
()
{
if
(
route
!
in
arrayOf
(
Acl
.
ALL
,
Acl
.
CUSTOM_RULES
))
AclSyncer
.
schedule
(
route
)
if
(
scheduleConfigUpdate
)
RemoteConfig
.
fetchAsync
()
}
fun
shutdown
(
scope
:
CoroutineScope
)
{
...
...
core/src/main/java/com/github/shadowsocks/bg/RemoteConfig.kt
deleted
100644 → 0
View file @
36576a61
/*******************************************************************************
* *
* Copyright (C) 2018 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2018 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
package
com.github.shadowsocks.bg
import
com.github.shadowsocks.core.R
import
com.google.firebase.analytics.ktx.analytics
import
com.google.firebase.analytics.ktx.logEvent
import
com.google.firebase.ktx.Firebase
import
com.google.firebase.remoteconfig.ktx.remoteConfig
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.GlobalScope
import
kotlinx.coroutines.async
import
kotlinx.coroutines.tasks.await
import
timber.log.Timber
object
RemoteConfig
{
private
val
config
=
GlobalScope
.
async
(
Dispatchers
.
Main
.
immediate
)
{
Firebase
.
remoteConfig
.
apply
{
setDefaultsAsync
(
R
.
xml
.
default_configs
).
await
()
}
}
fun
fetchAsync
()
=
GlobalScope
.
async
(
Dispatchers
.
Main
.
immediate
)
{
fetch
()
}
suspend
fun
fetch
()
=
config
.
await
().
run
{
try
{
fetch
().
await
()
this
to
true
}
catch
(
e
:
Exception
)
{
Timber
.
d
(
e
)
Firebase
.
analytics
.
logEvent
(
"femote_config_failure"
)
{
param
(
"message"
,
e
.
toString
())
}
this
to
false
}
}
}
core/src/main/java/com/github/shadowsocks/database/Profile.kt
View file @
8e17e4fb
...
...
@@ -101,7 +101,7 @@ data class Profile(
companion
object
{
private
const
val
serialVersionUID
=
1L
private
const
val
sponsored
=
"
198.199.101.152
"
private
const
val
sponsored
=
"
example.shadowsocks.org
"
private
val
pattern
=
"""(?i)ss://[-a-zA-Z0-9+&@#/%?=.~*'()|!:,;_\[\]]*[-a-zA-Z0-9+&@#/%=.~*'()|\[\]]"""
.
toRegex
()
private
val
userInfoPattern
=
"^(.+?):(.*)$"
.
toRegex
()
...
...
mobile/build.gradle.kts
View file @
8e17e4fb
...
...
@@ -17,10 +17,9 @@ dependencies {
implementation
(
"androidx.browser:browser:1.2.0"
)
implementation
(
"androidx.camera:camera-camera2:$cameraxVersion"
)
implementation
(
"androidx.camera:camera-lifecycle:$cameraxVersion"
)
implementation
(
"androidx.camera:camera-view:1.0.0-alpha1
7
"
)
implementation
(
"androidx.constraintlayout:constraintlayout:2.0.
1
"
)
implementation
(
"androidx.camera:camera-view:1.0.0-alpha1
9
"
)
implementation
(
"androidx.constraintlayout:constraintlayout:2.0.
4
"
)
implementation
(
"androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion"
)
implementation
(
"com.google.firebase:firebase-ads:19.4.0"
)
implementation
(
"com.google.mlkit:barcode-scanning:16.0.3"
)
implementation
(
"com.google.zxing:core:3.4.1"
)
implementation
(
"com.takisoft.preferencex:preferencex-simplemenu:1.1.0"
)
...
...
mobile/src/main/java/com/github/shadowsocks/AdsManager.kt
deleted
100644 → 0
View file @
36576a61
/*******************************************************************************
* *
* Copyright (C) 2020 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2020 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
package
com.github.shadowsocks
import
android.content.Context
import
com.google.android.gms.ads.AdLoader
import
com.google.android.gms.ads.AdRequest
import
com.google.android.gms.ads.MobileAds
import
com.google.android.gms.ads.RequestConfiguration
internal
object
AdsManager
{
init
{
MobileAds
.
setRequestConfiguration
(
RequestConfiguration
.
Builder
().
apply
{
setTestDeviceIds
(
listOf
(
"B08FC1764A7B250E91EA9D0D5EBEB208"
,
"7509D18EB8AF82F915874FEF53877A64"
,
"F58907F28184A828DD0DB6F8E38189C6"
,
"FE983F496D7C5C1878AA163D9420CA97"
))
}.
build
())
}
fun
load
(
context
:
Context
?,
setup
:
AdLoader
.
Builder
.()
->
Unit
)
=
AdLoader
.
Builder
(
context
,
"ca-app-pub-3283768469187309/8632513739"
).
apply
(
setup
).
build
()
.
loadAd
(
AdRequest
.
Builder
().
build
())
}
mobile/src/main/java/com/github/shadowsocks/ProfilesFragment.kt
View file @
8e17e4fb
...
...
@@ -56,10 +56,6 @@ import com.github.shadowsocks.utils.readableMessage
import
com.github.shadowsocks.widget.ListHolderListener
import
com.github.shadowsocks.widget.MainListListener
import
com.github.shadowsocks.widget.UndoSnackbarManager
import
com.google.android.gms.ads.VideoOptions
import
com.google.android.gms.ads.formats.NativeAdOptions
import
com.google.android.gms.ads.formats.UnifiedNativeAd
import
com.google.android.gms.ads.formats.UnifiedNativeAdView
import
com.google.zxing.BarcodeFormat
import
com.google.zxing.EncodeHintType
import
com.google.zxing.MultiFormatWriter
...
...
@@ -89,32 +85,6 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
private
fun
isProfileEditable
(
id
:
Long
)
=
(
activity
as
MainActivity
).
state
==
BaseService
.
State
.
Stopped
||
id
!
in
Core
.
activeProfileIds
private
var
nativeAd
:
UnifiedNativeAd
?
=
null
private
var
nativeAdView
:
UnifiedNativeAdView
?
=
null
private
var
adHost
:
ProfileViewHolder
?
=
null
private
fun
tryBindAd
()
=
lifecycleScope
.
launchWhenStarted
{
val
fp
=
layoutManager
.
findFirstVisibleItemPosition
()
if
(
fp
<
0
)
return
@launchWhenStarted
for
(
i
in
object
:
Iterator
<
Int
>
{
var
first
=
fp
var
last
=
layoutManager
.
findLastCompletelyVisibleItemPosition
()
var
flipper
=
false
override
fun
hasNext
()
=
first
<=
last
override
fun
next
():
Int
{
flipper
=
!
flipper
return
if
(
flipper
)
first
++
else
last--
}
}.
asSequence
().
toList
().
reversed
())
{
val
viewHolder
=
profilesList
.
findViewHolderForAdapterPosition
(
i
)
as
?
ProfileViewHolder
if
(
viewHolder
?.
item
?.
isSponsored
==
true
)
{
viewHolder
.
populateUnifiedNativeAdView
(
nativeAd
!!
,
nativeAdView
!!
)
// might be in the middle of a layout after scrolling, need to wait
withContext
(
Dispatchers
.
Main
)
{
profilesAdapter
.
notifyItemChanged
(
i
)
}
break
}
}
}
@SuppressLint
(
"ValidFragment"
)
class
QRCodeDialog
()
:
DialogFragment
()
{
constructor
(
url
:
String
)
:
this
()
{
...
...
@@ -157,7 +127,6 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
private
val
traffic
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
traffic
)
private
val
edit
=
itemView
.
findViewById
<
View
>(
R
.
id
.
edit
)
private
val
subscription
=
itemView
.
findViewById
<
View
>(
R
.
id
.
subscription
)
private
val
adContainer
=
itemView
.
findViewById
<
LinearLayout
>(
R
.
id
.
ad_container
)
init
{
edit
.
setOnClickListener
{
...
...
@@ -181,92 +150,6 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
TooltipCompat
.
setTooltipText
(
share
,
share
.
contentDescription
)
}
fun
populateUnifiedNativeAdView
(
nativeAd
:
UnifiedNativeAd
,
adView
:
UnifiedNativeAdView
)
{
// Set other ad assets.
adView
.
headlineView
=
adView
.
findViewById
(
R
.
id
.
ad_headline
)
adView
.
bodyView
=
adView
.
findViewById
(
R
.
id
.
ad_body
)
adView
.
callToActionView
=
adView
.
findViewById
(
R
.
id
.
ad_call_to_action
)
adView
.
iconView
=
adView
.
findViewById
(
R
.
id
.
ad_app_icon
)
adView
.
starRatingView
=
adView
.
findViewById
(
R
.
id
.
ad_stars
)
adView
.
advertiserView
=
adView
.
findViewById
(
R
.
id
.
ad_advertiser
)
// The headline and media content are guaranteed to be in every UnifiedNativeAd.
(
adView
.
headlineView
as
TextView
).
text
=
nativeAd
.
headline
// These assets aren't guaranteed to be in every UnifiedNativeAd, so it's important to
// check before trying to display them.
if
(
nativeAd
.
body
==
null
)
{
adView
.
bodyView
.
visibility
=
View
.
INVISIBLE
}
else
{
adView
.
bodyView
.
visibility
=
View
.
VISIBLE
(
adView
.
bodyView
as
TextView
).
text
=
nativeAd
.
body
}
if
(
nativeAd
.
callToAction
==
null
)
{
adView
.
callToActionView
.
visibility
=
View
.
INVISIBLE
}
else
{
adView
.
callToActionView
.
visibility
=
View
.
VISIBLE
(
adView
.
callToActionView
as
Button
).
text
=
nativeAd
.
callToAction
}
if
(
nativeAd
.
icon
==
null
)
{
adView
.
iconView
.
visibility
=
View
.
GONE
}
else
{
(
adView
.
iconView
as
ImageView
).
setImageDrawable
(
nativeAd
.
icon
.
drawable
)
adView
.
iconView
.
visibility
=
View
.
VISIBLE
}
if
(
nativeAd
.
starRating
==
null
)
{
adView
.
starRatingView
.
visibility
=
View
.
INVISIBLE
}
else
{
(
adView
.
starRatingView
as
RatingBar
).
rating
=
nativeAd
.
starRating
!!
.
toFloat
()
adView
.
starRatingView
.
visibility
=
View
.
VISIBLE
}
if
(
nativeAd
.
advertiser
==
null
)
{
adView
.
advertiserView
.
visibility
=
View
.
INVISIBLE
}
else
{
(
adView
.
advertiserView
as
TextView
).
text
=
nativeAd
.
advertiser
adView
.
advertiserView
.
visibility
=
View
.
VISIBLE
}
// This method tells the Google Mobile Ads SDK that you have finished populating your
// native ad view with this native ad.
adView
.
setNativeAd
(
nativeAd
)
adContainer
.
addView
(
adView
)
adHost
=
this
}
fun
attach
()
{
if
(
adHost
!=
null
||
!
item
.
isSponsored
)
return
if
(
nativeAdView
==
null
)
{
nativeAdView
=
layoutInflater
.
inflate
(
R
.
layout
.
ad_unified
,
adContainer
,
false
)
as
UnifiedNativeAdView
AdsManager
.
load
(
context
)
{
forUnifiedNativeAd
{
unifiedNativeAd
->
// You must call destroy on old ads when you are done with them,
// otherwise you will have a memory leak.
nativeAd
?.
destroy
()
nativeAd
=
unifiedNativeAd
tryBindAd
()
}
withNativeAdOptions
(
NativeAdOptions
.
Builder
().
apply
{
setVideoOptions
(
VideoOptions
.
Builder
().
apply
{
setStartMuted
(
true
)
}.
build
())
}.
build
())
}
}
else
if
(
nativeAd
!=
null
)
populateUnifiedNativeAdView
(
nativeAd
!!
,
nativeAdView
!!
)
}
fun
detach
()
{
if
(
adHost
==
this
)
{
adHost
=
null
adContainer
.
removeAllViews
()
tryBindAd
()
}
}
fun
bind
(
item
:
Profile
)
{
this
.
item
=
item
val
editable
=
isProfileEditable
(
item
.
id
)
...
...
@@ -341,8 +224,6 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
setHasStableIds
(
true
)
// see: http://stackoverflow.com/a/32488059/2245107
}
override
fun
onViewAttachedToWindow
(
holder
:
ProfileViewHolder
)
=
holder
.
attach
()
override
fun
onViewDetachedFromWindow
(
holder
:
ProfileViewHolder
)
=
holder
.
detach
()
override
fun
onBindViewHolder
(
holder
:
ProfileViewHolder
,
position
:
Int
)
=
holder
.
bind
(
profiles
[
position
])
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
ProfileViewHolder
=
ProfileViewHolder
(
LayoutInflater
.
from
(
parent
.
context
).
inflate
(
R
.
layout
.
layout_profile
,
parent
,
false
))
...
...
@@ -594,7 +475,6 @@ class ProfilesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
override
fun
onDestroyView
()
{
undoManager
.
flush
()
nativeAd
?.
destroy
()
super
.
onDestroyView
()
}
...
...
mobile/src/main/res/layout/ad_unified.xml
deleted
100644 → 0
View file @
36576a61
<com.google.android.gms.ads.formats.UnifiedNativeAdView
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:minHeight=
"40dp"
android:orientation=
"vertical"
>
<TextView
style=
"@style/Theme.Shadowsocks.AdAttribution"
/>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"vertical"
android:paddingTop=
"8dp"
>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<ImageView
android:id=
"@+id/ad_app_icon"
android:layout_width=
"40dp"
android:layout_height=
"40dp"
android:adjustViewBounds=
"true"
android:importantForAccessibility=
"no"
android:paddingBottom=
"5dp"
android:paddingEnd=
"5dp"
/>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"vertical"
>
<TextView
android:id=
"@+id/ad_headline"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:textColor=
"?android:attr/textColorPrimary"
android:maxLines=
"1"
android:textSize=
"14sp"
android:textStyle=
"bold"
/>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
>
<TextView
android:id=
"@+id/ad_advertiser"
android:layout_width=
"wrap_content"
android:layout_height=
"match_parent"
android:gravity=
"bottom"
android:textColor=
"?android:attr/textColorPrimary"
android:textSize=
"12sp"
android:textStyle=
"bold"
/>
<RatingBar
android:id=
"@+id/ad_stars"
style=
"?android:attr/ratingBarStyleSmall"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:isIndicator=
"true"
android:numStars=
"5"
android:stepSize=
"0.5"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"vertical"
>
<TextView
android:id=
"@+id/ad_body"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"start"
android:textColor=
"?android:attr/textColorSecondary"
android:textSize=
"12sp"
/>
<LinearLayout
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"end"
android:orientation=
"horizontal"
>
<Button
android:id=
"@+id/ad_call_to_action"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginEnd=
"12dp"
android:textColor=
"?android:attr/textColorPrimary"
android:gravity=
"center"
android:textSize=
"12sp"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</com.google.android.gms.ads.formats.UnifiedNativeAdView>
mobile/src/main/res/layout/layout_profile.xml
View file @
8e17e4fb
...
...
@@ -103,10 +103,4 @@
tools:text=
"@string/traffic"
/>
</RelativeLayout>
<LinearLayout
android:id=
"@+id/ad_container"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginLeft=
"16dp"
android:orientation=
"vertical"
/>
</LinearLayout>
repositories.gradle.kts
View file @
8e17e4fb
rootProject
.
extra
.
apply
{
set
(
"androidPlugin"
,
"com.android.tools.build:gradle:4.1.
0-rc03
"
)
set
(
"androidPlugin"
,
"com.android.tools.build:gradle:4.1.
1
"
)
set
(
"kotlinVersion"
,
"1.4.10"
)
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment