Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
appinventor-sources
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
xpstem
appinventor-sources
Commits
653d8d27
Commit
653d8d27
authored
Nov 21, 2019
by
kalsheikh
Committed by
Susan Rati Lane
Nov 21, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add adaptive icons (#1888)
parent
53262352
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
176 additions
and
4 deletions
+176
-4
appinventor/buildserver/src/com/google/appinventor/buildserver/Compiler.java
...rver/src/com/google/appinventor/buildserver/Compiler.java
+176
-4
appinventor/buildserver/src/com/google/appinventor/buildserver/resources/ya.png
...r/src/com/google/appinventor/buildserver/resources/ya.png
+0
-0
No files found.
appinventor/buildserver/src/com/google/appinventor/buildserver/Compiler.java
View file @
653d8d27
...
...
@@ -26,6 +26,10 @@ import org.codehaus.jettison.json.JSONException;
import
org.codehaus.jettison.json.JSONObject
;
import
org.codehaus.jettison.json.JSONTokener
;
import
java.awt.Graphics2D
;
import
java.awt.geom.Ellipse2D
;
import
java.awt.geom.RoundRectangle2D
;
import
java.awt.Image
;
import
java.awt.image.BufferedImage
;
import
java.io.BufferedReader
;
import
java.io.BufferedWriter
;
...
...
@@ -55,6 +59,7 @@ import java.util.concurrent.ConcurrentHashMap;
import
java.util.concurrent.ConcurrentMap
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
java.lang.Math
;
import
javax.imageio.ImageIO
;
...
...
@@ -778,6 +783,47 @@ public final class Compiler {
return
true
;
}
// Writes ic_launcher.xml to initialize adaptive icon
private
boolean
writeICLauncher
(
File
adaptiveIconFile
,
boolean
isRound
)
{
String
mainClass
=
project
.
getMainClass
();
String
packageName
=
Signatures
.
getPackageName
(
mainClass
);
try
{
BufferedWriter
out
=
new
BufferedWriter
(
new
OutputStreamWriter
(
new
FileOutputStream
(
adaptiveIconFile
),
"UTF-8"
));
out
.
write
(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
);
out
.
write
(
"<adaptive-icon "
+
"xmlns:android=\"http://schemas.android.com/apk/res/android\" "
+
">\n"
);
out
.
write
(
"<background android:drawable=\"@color/ic_launcher_background\" />\n"
);
if
(
isRound
)
{
out
.
write
(
"<foreground android:drawable=\"@mipmap/ic_launcher_round\" />\n"
);
}
else
{
out
.
write
(
"<foreground android:drawable=\"@mipmap/ic_launcher_foreground\" />\n"
);
}
out
.
write
(
"</adaptive-icon>\n"
);
out
.
close
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
userErrors
.
print
(
String
.
format
(
ERROR_IN_STAGE
,
"ic launcher"
));
return
false
;
}
return
true
;
}
// Writes ic_launcher_background.xml to indicate background color of adaptive icon
private
boolean
writeICLauncherBackground
(
File
icBackgroundFile
)
{
try
{
BufferedWriter
out
=
new
BufferedWriter
(
new
OutputStreamWriter
(
new
FileOutputStream
(
icBackgroundFile
),
"UTF-8"
));
out
.
write
(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
);
out
.
write
(
"<resources>\n"
);
out
.
write
(
"<color name=\"ic_launcher_background\">#ffffff</color>\n"
);
out
.
write
(
"</resources>\n"
);
out
.
close
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
userErrors
.
print
(
String
.
format
(
ERROR_IN_STAGE
,
"ic launcher background"
));
return
false
;
}
return
true
;
}
/*
* Creates an AndroidManifest.xml file needed for the Android application.
*/
...
...
@@ -891,7 +937,8 @@ public final class Compiler {
out
.
write
(
"android:label=\""
+
aName
+
"\" "
);
}
out
.
write
(
"android:networkSecurityConfig=\"@xml/network_security_config\" "
);
out
.
write
(
"android:icon=\"@drawable/ya\" "
);
out
.
write
(
"android:icon=\"@mipmap/ic_launcher\" "
);
out
.
write
(
"android:roundIcon=\"@mipmap/ic_launcher\" "
);
if
(
isForCompanion
)
{
// This is to hook into ACRA
out
.
write
(
"android:name=\"com.google.appinventor.components.runtime.ReplApplication\" "
);
}
else
{
...
...
@@ -1103,7 +1150,21 @@ public final class Compiler {
out
.
println
(
"________Preparing application icon"
);
File
resDir
=
createDir
(
buildDir
,
"res"
);
File
drawableDir
=
createDir
(
resDir
,
"drawable"
);
if
(!
compiler
.
prepareApplicationIcon
(
new
File
(
drawableDir
,
"ya.png"
)))
{
// Create mipmap directories
File
mipmapV26
=
createDir
(
resDir
,
"mipmap-anydpi-v26"
);
File
mipmapHdpi
=
createDir
(
resDir
,
"mipmap-hdpi"
);
File
mipmapMdpi
=
createDir
(
resDir
,
"mipmap-mdpi"
);
File
mipmapXhdpi
=
createDir
(
resDir
,
"mipmap-xhdpi"
);
File
mipmapXxhdpi
=
createDir
(
resDir
,
"mipmap-xxhdpi"
);
File
mipmapXxxhdpi
=
createDir
(
resDir
,
"mipmap-xxxhdpi"
);
// Create list of mipmaps for all icon types with respective sizes
List
<
File
>
mipmapDirectoriesForIcons
=
Arrays
.
asList
(
mipmapMdpi
,
mipmapHdpi
,
mipmapXhdpi
,
mipmapXxhdpi
,
mipmapXxxhdpi
);
List
<
Integer
>
standardICSizesForMipmaps
=
Arrays
.
asList
(
48
,
72
,
96
,
144
,
192
);
List
<
Integer
>
foregroundICSizesForMipmaps
=
Arrays
.
asList
(
108
,
162
,
216
,
324
,
432
);
if
(!
compiler
.
prepareApplicationIcon
(
new
File
(
drawableDir
,
"ya.png"
),
mipmapDirectoriesForIcons
,
standardICSizesForMipmaps
,
foregroundICSizesForMipmaps
))
{
return
false
;
}
if
(
reporter
!=
null
)
{
...
...
@@ -1143,6 +1204,27 @@ public final class Compiler {
return
false
;
}
// Generate ic_launcher.xml
out
.
println
(
"________Generating adaptive icon file"
);
File
icLauncher
=
new
File
(
mipmapV26
,
"ic_launcher.xml"
);
if
(!
compiler
.
writeICLauncher
(
icLauncher
,
false
))
{
return
false
;
}
// Generate ic_launcher_round.xml
out
.
println
(
"________Generating round adaptive icon file"
);
File
icLauncherRound
=
new
File
(
mipmapV26
,
"ic_launcher_round.xml"
);
if
(!
compiler
.
writeICLauncher
(
icLauncherRound
,
true
))
{
return
false
;
}
// Generate ic_launcher_background.xml
out
.
println
(
"________Generating adaptive icon background file"
);
File
icBackgroundColor
=
new
File
(
styleDir
,
"ic_launcher_background.xml"
);
if
(!
compiler
.
writeICLauncherBackground
(
icBackgroundColor
))
{
return
false
;
}
// Generate AndroidManifest.xml
out
.
println
(
"________Generating manifest file"
);
File
manifestFile
=
new
File
(
buildDir
,
"AndroidManifest.xml"
);
...
...
@@ -1627,10 +1709,76 @@ public final class Compiler {
return
true
;
}
/*
* Returns a resized image given a new width and height
*/
private
BufferedImage
resizeImage
(
BufferedImage
icon
,
int
height
,
int
width
)
{
Image
tmp
=
icon
.
getScaledInstance
(
width
,
height
,
Image
.
SCALE_SMOOTH
);
BufferedImage
finalResized
=
new
BufferedImage
(
width
,
height
,
BufferedImage
.
TYPE_INT_ARGB
);
Graphics2D
g2
=
finalResized
.
createGraphics
();
g2
.
drawImage
(
tmp
,
0
,
0
,
null
);
return
finalResized
;
}
/*
* Creates the circle image of an icon
*/
private
BufferedImage
produceRoundIcon
(
BufferedImage
icon
)
{
int
imageWidth
=
icon
.
getWidth
();
// Ratio of icon size to png image size for round icon is 0.80
double
iconWidth
=
imageWidth
*
0.80
;
// Round iconWidth value to even int for a centered png
int
intIconWidth
=
((
int
)
Math
.
round
(
iconWidth
/
2
)
*
2
);
Image
tmp
=
icon
.
getScaledInstance
(
intIconWidth
,
intIconWidth
,
Image
.
SCALE_SMOOTH
);
int
marginWidth
=
((
imageWidth
-
intIconWidth
)
/
2
);
BufferedImage
roundIcon
=
new
BufferedImage
(
imageWidth
,
imageWidth
,
BufferedImage
.
TYPE_INT_ARGB
);
Graphics2D
g2
=
roundIcon
.
createGraphics
();
g2
.
setClip
(
new
Ellipse2D
.
Float
(
marginWidth
,
marginWidth
,
intIconWidth
,
intIconWidth
));
g2
.
drawImage
(
tmp
,
marginWidth
,
marginWidth
,
null
);
return
roundIcon
;
}
/*
* Creates the image of an icon with rounded corners
*/
private
BufferedImage
produceRoundedCornerIcon
(
BufferedImage
icon
)
{
int
imageWidth
=
icon
.
getWidth
();
// Ratio of icon size to png image size for roundRect icon is 0.93
double
iconWidth
=
imageWidth
*
0.93
;
// Round iconWidth value to even int for a centered png
int
intIconWidth
=
((
int
)
Math
.
round
(
iconWidth
/
2
)
*
2
);
Image
tmp
=
icon
.
getScaledInstance
(
intIconWidth
,
intIconWidth
,
Image
.
SCALE_SMOOTH
);
int
marginWidth
=
((
imageWidth
-
intIconWidth
)
/
2
);
// Corner radius of roundedCornerIcon needs to be 1/12 of width according to Android material guidelines
float
cornerRadius
=
intIconWidth
/
12
;
BufferedImage
roundedCornerIcon
=
new
BufferedImage
(
imageWidth
,
imageWidth
,
BufferedImage
.
TYPE_INT_ARGB
);
Graphics2D
g2
=
roundedCornerIcon
.
createGraphics
();
g2
.
setClip
(
new
RoundRectangle2D
.
Float
(
marginWidth
,
marginWidth
,
intIconWidth
,
intIconWidth
,
cornerRadius
,
cornerRadius
));
g2
.
drawImage
(
tmp
,
marginWidth
,
marginWidth
,
null
);
return
roundedCornerIcon
;
}
/*
* Creates the foreground image of an icon
*/
private
BufferedImage
produceForegroundImageIcon
(
BufferedImage
icon
)
{
int
imageWidth
=
icon
.
getWidth
();
// Ratio of icon size to png image size for foreground/round icon is 0.80
double
iconWidth
=
imageWidth
*
0.80
;
// Round iconWidth value to even int for a centered png
int
intIconWidth
=
((
int
)
Math
.
round
(
iconWidth
/
2
)
*
2
);
Image
tmp
=
icon
.
getScaledInstance
(
intIconWidth
,
intIconWidth
,
Image
.
SCALE_SMOOTH
);
int
marginWidth
=
((
imageWidth
-
intIconWidth
)
/
2
);
BufferedImage
foregroundImageIcon
=
new
BufferedImage
(
imageWidth
,
imageWidth
,
BufferedImage
.
TYPE_INT_ARGB
);
Graphics2D
g2
=
foregroundImageIcon
.
createGraphics
();
g2
.
drawImage
(
tmp
,
marginWidth
,
marginWidth
,
null
);
return
foregroundImageIcon
;
}
/*
* Loads the icon for the application, either a user provided one or the default one.
*/
private
boolean
prepareApplicationIcon
(
File
outputPngFile
)
{
private
boolean
prepareApplicationIcon
(
File
outputPngFile
,
List
<
File
>
mipmapDirectories
,
List
<
Integer
>
standardICSizes
,
List
<
Integer
>
foregroundICSizes
)
{
String
userSpecifiedIcon
=
Strings
.
nullToEmpty
(
project
.
getIcon
());
try
{
BufferedImage
icon
;
...
...
@@ -1640,7 +1788,8 @@ public final class Compiler {
if
(
icon
==
null
)
{
// This can happen if the iconFile isn't an image file.
// For example, icon is null if the file is a .wav file.
// TODO(lizlooney) - This happens if the user specifies a .ico file. We should fix that.
// TODO(lizlooney) - This happens if the user specifies a .ico file. We should
// fix that.
userErrors
.
print
(
String
.
format
(
ICON_ERROR
,
userSpecifiedIcon
));
return
false
;
}
...
...
@@ -1648,6 +1797,29 @@ public final class Compiler {
// Load the default image.
icon
=
ImageIO
.
read
(
Compiler
.
class
.
getResource
(
DEFAULT_ICON
));
}
BufferedImage
roundIcon
=
produceRoundIcon
(
icon
);
BufferedImage
roundRectIcon
=
produceRoundedCornerIcon
(
icon
);
BufferedImage
foregroundIcon
=
produceForegroundImageIcon
(
icon
);
// For each mipmap directory, create all types of ic_launcher photos with respective mipmap sizes
for
(
int
i
=
0
;
i
<
mipmapDirectories
.
size
();
i
++){
File
mipmapDirectory
=
mipmapDirectories
.
get
(
i
);
Integer
standardSize
=
standardICSizes
.
get
(
i
);
Integer
foregroundSize
=
foregroundICSizes
.
get
(
i
);
BufferedImage
round
=
resizeImage
(
roundIcon
,
standardSize
,
standardSize
);
BufferedImage
roundRect
=
resizeImage
(
roundRectIcon
,
standardSize
,
standardSize
);
BufferedImage
foreground
=
resizeImage
(
foregroundIcon
,
foregroundSize
,
foregroundSize
);
File
roundIconPng
=
new
File
(
mipmapDirectory
,
"ic_launcher_round.png"
);
File
roundRectIconPng
=
new
File
(
mipmapDirectory
,
"ic_launcher.png"
);
File
foregroundPng
=
new
File
(
mipmapDirectory
,
"ic_launcher_foreground.png"
);
ImageIO
.
write
(
round
,
"png"
,
roundIconPng
);
ImageIO
.
write
(
roundRect
,
"png"
,
roundRectIconPng
);
ImageIO
.
write
(
foreground
,
"png"
,
foregroundPng
);
}
ImageIO
.
write
(
icon
,
"png"
,
outputPngFile
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
...
...
appinventor/buildserver/src/com/google/appinventor/buildserver/resources/ya.png
View replaced file @
53262352
View file @
653d8d27
3.48 KB
|
W:
|
H:
70.7 KB
|
W:
|
H:
2-up
Swipe
Onion skin
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