OSDN Git Service

Expose fonts.xml via public API with a service
authorClara Bayarri <clarabayarri@google.com>
Tue, 10 Jan 2017 17:31:51 +0000 (09:31 -0800)
committerClara Bayarri <clarabayarri@google.com>
Mon, 23 Jan 2017 15:02:23 +0000 (15:02 +0000)
This change creates a new FontManagerService, in charge of providing
font management data. It exposes a public API to retrieve the
information in fonts.xml without accessing it directly. To do this,
it also refactors FontListParser's internal classes into a new public
FontConfig class holding all the font data.

getSystemFonts() returns all the available information in fonts.xml
as well as file descriptors for all the fonts. This allows us to
share the memory consumed by these files between all clients.

Bug: 34190490
Test: See attached CTS change in topic
Change-Id: I0e922f8bcc9a197a1988d04071eb485328d66fb7

22 files changed:
Android.mk
api/current.txt
api/system-current.txt
api/test-current.txt
compiled-classes-phone
core/java/android/app/SystemServiceRegistry.java
core/java/android/content/Context.java
core/java/android/text/FontConfig.aidl [new file with mode: 0644]
core/java/android/text/FontConfig.java [new file with mode: 0644]
core/java/android/text/FontManager.java [new file with mode: 0644]
core/java/com/android/internal/font/IFontManager.aidl [new file with mode: 0644]
core/jni/android/graphics/FontFamily.cpp
core/jni/android/graphics/FontUtils.cpp [new file with mode: 0644]
graphics/java/android/graphics/FontFamily.java
graphics/java/android/graphics/FontListParser.java
graphics/java/android/graphics/Typeface.java
graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
preloaded-classes
services/core/java/com/android/server/FontManagerService.java [new file with mode: 0644]
services/java/com/android/server/SystemServer.java
tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java

index 21bd76b..2539c3d 100644 (file)
@@ -346,6 +346,7 @@ LOCAL_SRC_FILES += \
        core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
        core/java/com/android/internal/backup/IBackupTransport.aidl \
        core/java/com/android/internal/backup/IObbBackupService.aidl \
+       core/java/com/android/internal/font/IFontManager.aidl \
        core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl \
        core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl \
        core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl \
index 2b07a5c..be0cab8 100644 (file)
@@ -8472,6 +8472,7 @@ package android.content {
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
+    field public static final java.lang.String FONT_SERVICE = "font";
     field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
@@ -39449,6 +39450,65 @@ package android.text {
     method public android.text.Editable newEditable(java.lang.CharSequence);
   }
 
+  public final class FontConfig implements android.os.Parcelable {
+    ctor public FontConfig();
+    ctor public FontConfig(android.text.FontConfig);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Alias> getAliases();
+    method public java.util.List<android.text.FontConfig.Family> getFamilies();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
+  }
+
+  public static final class FontConfig.Alias implements android.os.Parcelable {
+    ctor public FontConfig.Alias(java.lang.String, java.lang.String, int);
+    method public int describeContents();
+    method public java.lang.String getName();
+    method public java.lang.String getToName();
+    method public int getWeight();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR;
+  }
+
+  public static final class FontConfig.Axis implements android.os.Parcelable {
+    ctor public FontConfig.Axis(int, float);
+    method public int describeContents();
+    method public float getStyleValue();
+    method public int getTag();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Axis> CREATOR;
+  }
+
+  public static final class FontConfig.Family implements android.os.Parcelable {
+    ctor public FontConfig.Family(java.lang.String, java.util.List<android.text.FontConfig.Font>, java.lang.String, java.lang.String);
+    ctor public FontConfig.Family(android.text.FontConfig.Family);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Font> getFonts();
+    method public java.lang.String getLanguage();
+    method public java.lang.String getName();
+    method public java.lang.String getVariant();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Family> CREATOR;
+  }
+
+  public static final class FontConfig.Font implements android.os.Parcelable {
+    ctor public FontConfig.Font(java.lang.String, int, java.util.List<android.text.FontConfig.Axis>, int, boolean);
+    ctor public FontConfig.Font(android.text.FontConfig.Font);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Axis> getAxes();
+    method public android.os.ParcelFileDescriptor getFd();
+    method public java.lang.String getFontName();
+    method public int getTtcIndex();
+    method public int getWeight();
+    method public boolean isItalic();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR;
+  }
+
+  public final class FontManager {
+    method public android.text.FontConfig getSystemFonts();
+  }
+
   public abstract interface GetChars implements java.lang.CharSequence {
     method public abstract void getChars(int, int, char[], int);
   }
index 7cb8aaf..bb8d7fc 100644 (file)
@@ -8847,6 +8847,7 @@ package android.content {
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
+    field public static final java.lang.String FONT_SERVICE = "font";
     field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
@@ -42724,6 +42725,65 @@ package android.text {
     method public android.text.Editable newEditable(java.lang.CharSequence);
   }
 
+  public final class FontConfig implements android.os.Parcelable {
+    ctor public FontConfig();
+    ctor public FontConfig(android.text.FontConfig);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Alias> getAliases();
+    method public java.util.List<android.text.FontConfig.Family> getFamilies();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
+  }
+
+  public static final class FontConfig.Alias implements android.os.Parcelable {
+    ctor public FontConfig.Alias(java.lang.String, java.lang.String, int);
+    method public int describeContents();
+    method public java.lang.String getName();
+    method public java.lang.String getToName();
+    method public int getWeight();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR;
+  }
+
+  public static final class FontConfig.Axis implements android.os.Parcelable {
+    ctor public FontConfig.Axis(int, float);
+    method public int describeContents();
+    method public float getStyleValue();
+    method public int getTag();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Axis> CREATOR;
+  }
+
+  public static final class FontConfig.Family implements android.os.Parcelable {
+    ctor public FontConfig.Family(java.lang.String, java.util.List<android.text.FontConfig.Font>, java.lang.String, java.lang.String);
+    ctor public FontConfig.Family(android.text.FontConfig.Family);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Font> getFonts();
+    method public java.lang.String getLanguage();
+    method public java.lang.String getName();
+    method public java.lang.String getVariant();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Family> CREATOR;
+  }
+
+  public static final class FontConfig.Font implements android.os.Parcelable {
+    ctor public FontConfig.Font(java.lang.String, int, java.util.List<android.text.FontConfig.Axis>, int, boolean);
+    ctor public FontConfig.Font(android.text.FontConfig.Font);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Axis> getAxes();
+    method public android.os.ParcelFileDescriptor getFd();
+    method public java.lang.String getFontName();
+    method public int getTtcIndex();
+    method public int getWeight();
+    method public boolean isItalic();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR;
+  }
+
+  public final class FontManager {
+    method public android.text.FontConfig getSystemFonts();
+  }
+
   public abstract interface GetChars implements java.lang.CharSequence {
     method public abstract void getChars(int, int, char[], int);
   }
index 82715b3..bd530fc 100644 (file)
@@ -8496,6 +8496,7 @@ package android.content {
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
+    field public static final java.lang.String FONT_SERVICE = "font";
     field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
@@ -39573,6 +39574,65 @@ package android.text {
     method public android.text.Editable newEditable(java.lang.CharSequence);
   }
 
+  public final class FontConfig implements android.os.Parcelable {
+    ctor public FontConfig();
+    ctor public FontConfig(android.text.FontConfig);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Alias> getAliases();
+    method public java.util.List<android.text.FontConfig.Family> getFamilies();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
+  }
+
+  public static final class FontConfig.Alias implements android.os.Parcelable {
+    ctor public FontConfig.Alias(java.lang.String, java.lang.String, int);
+    method public int describeContents();
+    method public java.lang.String getName();
+    method public java.lang.String getToName();
+    method public int getWeight();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR;
+  }
+
+  public static final class FontConfig.Axis implements android.os.Parcelable {
+    ctor public FontConfig.Axis(int, float);
+    method public int describeContents();
+    method public float getStyleValue();
+    method public int getTag();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Axis> CREATOR;
+  }
+
+  public static final class FontConfig.Family implements android.os.Parcelable {
+    ctor public FontConfig.Family(java.lang.String, java.util.List<android.text.FontConfig.Font>, java.lang.String, java.lang.String);
+    ctor public FontConfig.Family(android.text.FontConfig.Family);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Font> getFonts();
+    method public java.lang.String getLanguage();
+    method public java.lang.String getName();
+    method public java.lang.String getVariant();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Family> CREATOR;
+  }
+
+  public static final class FontConfig.Font implements android.os.Parcelable {
+    ctor public FontConfig.Font(java.lang.String, int, java.util.List<android.text.FontConfig.Axis>, int, boolean);
+    ctor public FontConfig.Font(android.text.FontConfig.Font);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Axis> getAxes();
+    method public android.os.ParcelFileDescriptor getFd();
+    method public java.lang.String getFontName();
+    method public int getTtcIndex();
+    method public int getWeight();
+    method public boolean isItalic();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR;
+  }
+
+  public final class FontManager {
+    method public android.text.FontConfig getSystemFonts();
+  }
+
   public abstract interface GetChars implements java.lang.CharSequence {
     method public abstract void getChars(int, int, char[], int);
   }
index ebc54f2..ed0a4a6 100644 (file)
@@ -1195,13 +1195,13 @@ android.graphics.DashPathEffect
 android.graphics.DiscretePathEffect
 android.graphics.DrawFilter
 android.graphics.EmbossMaskFilter
+android.graphics.FontConfig
+android.graphics.FontConfig$Alias
+android.graphics.FontConfig$Axis
+android.graphics.FontConfig$Family
+android.graphics.FontConfig$Font
 android.graphics.FontFamily
 android.graphics.FontListParser
-android.graphics.FontListParser$Alias
-android.graphics.FontListParser$Axis
-android.graphics.FontListParser$Config
-android.graphics.FontListParser$Family
-android.graphics.FontListParser$Font
 android.graphics.ImageFormat
 android.graphics.Insets
 android.graphics.Interpolator
index 9387019..a37f22b 100644 (file)
@@ -118,6 +118,7 @@ import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.text.FontManager;
 import android.text.TextClassificationManager;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
@@ -133,6 +134,7 @@ import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.app.ISoundTriggerService;
 import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.font.IFontManager;
 import com.android.internal.os.IDropBoxManagerService;
 import com.android.internal.policy.PhoneLayoutInflater;
 
@@ -793,6 +795,15 @@ final class SystemServiceRegistry {
             public IncidentManager createService(ContextImpl ctx) throws ServiceNotFoundException {
                 return new IncidentManager(ctx);
             }});
+
+        registerService(Context.FONT_SERVICE, FontManager.class,
+                new CachedServiceFetcher<FontManager>() {
+                    @Override
+                    public FontManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getServiceOrThrow(Context.FONT_SERVICE);
+                        return new FontManager(IFontManager.Stub.asInterface(b));
+                    }});
     }
 
     /**
index 596a9fd..f41d7f2 100644 (file)
@@ -3744,6 +3744,11 @@ public abstract class Context {
     public static final String DEVICE_IDENTIFIERS_SERVICE = "device_identifiers";
 
     /**
+     * Service that provides System font data.
+     */
+    public static final String FONT_SERVICE = "font";
+
+    /**
      * Service to report a system health "incident"
      * @hide
      */
diff --git a/core/java/android/text/FontConfig.aidl b/core/java/android/text/FontConfig.aidl
new file mode 100644 (file)
index 0000000..17a5ca2
--- /dev/null
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * 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 android.text;
+
+/** @hide */
+parcelable FontConfig;
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
new file mode 100644 (file)
index 0000000..df694ff
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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 android.text;
+
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Font configuration descriptions for System fonts.
+ */
+public final class FontConfig implements Parcelable {
+    private final List<Family> mFamilies = new ArrayList<>();
+    private final List<Alias> mAliases = new ArrayList<>();
+
+    public FontConfig() {
+    }
+
+    public FontConfig(FontConfig config) {
+        for (int i = 0; i < config.mFamilies.size(); i++) {
+            mFamilies.add(new Family(config.mFamilies.get(i)));
+        }
+        mAliases.addAll(config.mAliases);
+    }
+
+    /**
+     * Returns the ordered list of families included in the system fonts.
+     */
+    public List<Family> getFamilies() {
+        return mFamilies;
+    }
+
+    /**
+     * Returns the list of aliases defined for the font families in the system fonts.
+     */
+    public List<Alias> getAliases() {
+        return mAliases;
+    }
+
+    /**
+     * @hide
+     */
+    public FontConfig(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flag) {
+        out.writeInt(mFamilies.size());
+        for (int i = 0; i < mFamilies.size(); i++) {
+            mFamilies.get(i).writeToParcel(out, flag);
+        }
+        out.writeInt(mAliases.size());
+        for (int i = 0; i < mAliases.size(); i++) {
+            mAliases.get(i).writeToParcel(out, flag);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public void readFromParcel(Parcel in) {
+        int size = in.readInt();
+        for (int i = 0; i < size; i++) {
+            mFamilies.add(new Family(in));
+        }
+        size = in.readInt();
+        for (int i = 0; i < size; i++) {
+            mAliases.add(new Alias(in));
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<FontConfig> CREATOR = new Parcelable.Creator() {
+        public FontConfig createFromParcel(Parcel in) {
+            return new FontConfig(in);
+        }
+        public FontConfig[] newArray(int size) {
+            return new FontConfig[size];
+        }
+    };
+
+    /**
+     * Class that holds information about a Font axis.
+     */
+    public static final class Axis implements Parcelable {
+        private final int mTag;
+        private final float mStyleValue;
+
+        public Axis(int tag, float styleValue) {
+            this.mTag = tag;
+            this.mStyleValue = styleValue;
+        }
+
+        /**
+         * Returns the variable font axis tag associated to this axis.
+         */
+        public int getTag() {
+            return mTag;
+        }
+
+        /**
+         * Returns the style value associated to the given axis for this font.
+         */
+        public float getStyleValue() {
+            return mStyleValue;
+        }
+
+        /**
+         * @hide
+         */
+        public Axis(Parcel in) {
+            mTag = in.readInt();
+            mStyleValue = in.readFloat();
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flag) {
+            out.writeInt(mTag);
+            out.writeFloat(mStyleValue);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<Axis> CREATOR = new Creator<Axis>() {
+            @Override
+            public Axis createFromParcel(Parcel in) {
+                return new Axis(in);
+            }
+
+            @Override
+            public Axis[] newArray(int size) {
+                return new Axis[size];
+            }
+        };
+    }
+
+    /**
+     * Class that holds information about a Font.
+     */
+    public static final class Font implements Parcelable {
+        private final String mFontName;
+        private final int mTtcIndex;
+        private final List<Axis> mAxes;
+        private final int mWeight;
+        private final boolean mIsItalic;
+        private ParcelFileDescriptor mFd;
+
+        public Font(String fontName, int ttcIndex, List<Axis> axes, int weight, boolean isItalic) {
+            mFontName = fontName;
+            mTtcIndex = ttcIndex;
+            mAxes = axes;
+            mWeight = weight;
+            mIsItalic = isItalic;
+            mFd = null;
+        }
+
+        public Font(Font origin) {
+            mFontName = origin.mFontName;
+            mTtcIndex = origin.mTtcIndex;
+            mAxes = new ArrayList<>(origin.mAxes);
+            mWeight = origin.mWeight;
+            mIsItalic = origin.mIsItalic;
+            if (origin.mFd != null) {
+                try {
+                    mFd = origin.mFd.dup();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        /**
+         * Returns the name associated by the system to this font.
+         */
+        public String getFontName() {
+            return mFontName;
+        }
+
+        /**
+         * Returns the index to be used to access this font when accessing a TTC file.
+         */
+        public int getTtcIndex() {
+            return mTtcIndex;
+        }
+
+        /**
+         * Returns the list of axes associated to this font.
+         */
+        public List<Axis> getAxes() {
+            return mAxes;
+        }
+
+        /**
+         * Returns the weight value for this font.
+         */
+        public int getWeight() {
+            return mWeight;
+        }
+
+        /**
+         * Returns whether this font is italic.
+         */
+        public boolean isItalic() {
+            return mIsItalic;
+        }
+
+        /**
+         * Returns a file descriptor to access the specified font. This should be closed after use.
+         */
+        public ParcelFileDescriptor getFd() {
+            return mFd;
+        }
+
+        /**
+         * @hide
+         */
+        public void setFd(ParcelFileDescriptor fd) {
+            mFd = fd;
+        }
+
+        /**
+         * @hide
+         */
+        public Font(Parcel in) {
+            mFontName = in.readString();
+            mTtcIndex = in.readInt();
+            final int numAxes = in.readInt();
+            mAxes = new ArrayList<>();
+            for (int i = 0; i < numAxes; i++) {
+                mAxes.add(new Axis(in));
+            }
+            mWeight = in.readInt();
+            mIsItalic = in.readInt() == 1;
+            if (in.readInt() == 1) { /* has FD */
+                mFd = ParcelFileDescriptor.CREATOR.createFromParcel(in);
+            } else {
+                mFd = null;
+            }
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flag) {
+            out.writeString(mFontName);
+            out.writeInt(mTtcIndex);
+            out.writeInt(mAxes.size());
+            for (int i = 0; i < mAxes.size(); i++) {
+                mAxes.get(i).writeToParcel(out, flag);
+            }
+            out.writeInt(mWeight);
+            out.writeInt(mIsItalic ? 1 : 0);
+            out.writeInt(mFd == null ? 0 : 1);
+            if (mFd != null) {
+                mFd.writeToParcel(out, flag);
+            }
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<Font> CREATOR = new Creator<Font>() {
+            @Override
+            public Font createFromParcel(Parcel in) {
+                return new Font(in);
+            }
+
+            @Override
+            public Font[] newArray(int size) {
+                return new Font[size];
+            }
+        };
+    }
+
+    /**
+     * Class that holds information about a Font alias.
+     */
+    public static final class Alias implements Parcelable {
+        private final String mName;
+        private final String mToName;
+        private final int mWeight;
+
+        public Alias(String name, String toName, int weight) {
+            this.mName = name;
+            this.mToName = toName;
+            this.mWeight = weight;
+        }
+
+        /**
+         * Returns the new name for the alias.
+         */
+        public String getName() {
+            return mName;
+        }
+
+        /**
+         * Returns the existing name to which this alias points to.
+         */
+        public String getToName() {
+            return mToName;
+        }
+
+        /**
+         * Returns the weight associated with this alias.
+         */
+        public int getWeight() {
+            return mWeight;
+        }
+
+        /**
+         * @hide
+         */
+        public Alias(Parcel in) {
+            mName = in.readString();
+            mToName = in.readString();
+            mWeight = in.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flag) {
+            out.writeString(mName);
+            out.writeString(mToName);
+            out.writeInt(mWeight);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<Alias> CREATOR = new Creator<Alias>() {
+            @Override
+            public Alias createFromParcel(Parcel in) {
+                return new Alias(in);
+            }
+
+            @Override
+            public Alias[] newArray(int size) {
+                return new Alias[size];
+            }
+        };
+    }
+
+    /**
+     * Class that holds information about a Font family.
+     */
+    public static final class Family implements Parcelable {
+        private final String mName;
+        private final List<Font> mFonts;
+        private final String mLanguage;
+        private final String mVariant;
+
+        public Family(String name, List<Font> fonts, String language, String variant) {
+            this.mName = name;
+            this.mFonts = fonts;
+            this.mLanguage = language;
+            this.mVariant = variant;
+        }
+
+        public Family(Family origin) {
+            this.mName = origin.mName;
+            this.mLanguage = origin.mLanguage;
+            this.mVariant = origin.mVariant;
+            this.mFonts = new ArrayList<>();
+            for (int i = 0; i < origin.mFonts.size(); i++) {
+                mFonts.add(new Font(origin.mFonts.get(i)));
+            }
+        }
+
+        /**
+         * Returns the name given by the system to this font family.
+         */
+        public String getName() {
+            return mName;
+        }
+
+        /**
+         * Returns the list of fonts included in this family.
+         */
+        public List<Font> getFonts() {
+            return mFonts;
+        }
+
+        /**
+         * Returns the language for this family. May be null.
+         */
+        public String getLanguage() {
+            return mLanguage;
+        }
+
+        /**
+         * Returns the font variant for this family, e.g. "elegant" or "compact". May be null.
+         */
+        public String getVariant() {
+            return mVariant;
+        }
+
+        /**
+         * @hide
+         */
+        public Family(Parcel in) {
+            mName = in.readString();
+            final int size = in.readInt();
+            mFonts = new ArrayList<>();
+            for (int i = 0; i < size; i++) {
+                mFonts.add(new Font(in));
+            }
+            mLanguage = in.readString();
+            mVariant = in.readString();
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flag) {
+            out.writeString(mName);
+            out.writeInt(mFonts.size());
+            for (int i = 0; i < mFonts.size(); i++) {
+                mFonts.get(i).writeToParcel(out, flag);
+            }
+            out.writeString(mLanguage);
+            out.writeString(mVariant);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<Family> CREATOR = new Creator<Family>() {
+            @Override
+            public Family createFromParcel(Parcel in) {
+                return new Family(in);
+            }
+
+            @Override
+            public Family[] newArray(int size) {
+                return new Family[size];
+            }
+        };
+    }
+}
diff --git a/core/java/android/text/FontManager.java b/core/java/android/text/FontManager.java
new file mode 100644 (file)
index 0000000..b61cbf3
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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 android.text;
+
+import android.os.RemoteException;
+
+import com.android.internal.font.IFontManager;
+
+/**
+ * Interact with the Font service.
+ */
+public final class FontManager {
+    private static final String TAG = "FontManager";
+
+    private final IFontManager mService;
+
+    /**
+     * @hide
+     */
+    public FontManager(IFontManager service) {
+        mService = service;
+    }
+
+    /**
+     * Retrieve the system fonts data. This loads the fonts.xml data if needed and loads all system
+     * fonts in to memory, providing file descriptors for them.
+     */
+    public FontConfig getSystemFonts() {
+        try {
+            return mService.getSystemFonts();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/com/android/internal/font/IFontManager.aidl b/core/java/com/android/internal/font/IFontManager.aidl
new file mode 100644 (file)
index 0000000..52a6262
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.android.internal.font;
+
+import android.text.FontConfig;
+
+/**
+ * Interface to the font manager.
+ * @hide
+ */
+interface IFontManager {
+    FontConfig getSystemFonts();
+}
index 15e7165..15df219 100644 (file)
@@ -247,9 +247,9 @@ int register_android_graphics_FontFamily(JNIEnv* env)
     gListClassInfo.mGet = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;");
     gListClassInfo.mSize = GetMethodIDOrDie(env, listClass, "size", "()I");
 
-    jclass axisClass = FindClassOrDie(env, "android/graphics/FontListParser$Axis");
-    gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "tag", "I");
-    gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "styleValue", "F");
+    jclass axisClass = FindClassOrDie(env, "android/text/FontConfig$Axis");
+    gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "mTag", "I");
+    gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "mStyleValue", "F");
 
     return err;
 }
diff --git a/core/jni/android/graphics/FontUtils.cpp b/core/jni/android/graphics/FontUtils.cpp
new file mode 100644 (file)
index 0000000..91fec2a
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "FontUtils.h"
+
+#include "JNIHelp.h"
+#include <core_jni_helpers.h>
+
+namespace android {
+namespace {
+
+static struct {
+    jmethodID mGet;
+    jmethodID mSize;
+} gListClassInfo;
+
+static struct {
+    jfieldID mTag;
+    jfieldID mStyleValue;
+} gAxisClassInfo;
+
+}  // namespace
+
+jint ListHelper::size() const {
+    return mEnv->CallIntMethod(mList, gListClassInfo.mSize);
+}
+
+jobject ListHelper::get(jint index) const {
+    return mEnv->CallObjectMethod(mList, gListClassInfo.mGet, index);
+}
+
+jint AxisHelper::getTag() const {
+    return mEnv->GetIntField(mAxis, gAxisClassInfo.mTag);
+}
+
+jfloat AxisHelper::getStyleValue() const {
+    return mEnv->GetFloatField(mAxis, gAxisClassInfo.mStyleValue);
+}
+
+void init_FontUtils(JNIEnv* env) {
+    jclass listClass = FindClassOrDie(env, "java/util/List");
+    gListClassInfo.mGet = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;");
+    gListClassInfo.mSize = GetMethodIDOrDie(env, listClass, "size", "()I");
+
+    jclass axisClass = FindClassOrDie(env, "android/text/FontConfig$Axis");
+    gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "mTag", "I");
+    gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "mStyleValue", "F");
+}
+
+}  // namespace android
index e48bf79..07acd59 100644 (file)
@@ -17,6 +17,7 @@
 package android.graphics;
 
 import android.content.res.AssetManager;
+import android.text.FontConfig;
 import android.util.Log;
 
 import java.io.FileInputStream;
@@ -80,7 +81,7 @@ public class FontFamily {
         }
     }
 
-    public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, List<FontListParser.Axis> axes,
+    public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, List<FontConfig.Axis> axes,
             int weight, boolean style) {
         return nAddFontWeightStyle(mNativePtr, font, ttcIndex, axes, weight, style);
     }
@@ -93,7 +94,7 @@ public class FontFamily {
     private static native void nUnrefFamily(long nativePtr);
     private static native boolean nAddFont(long nativeFamily, ByteBuffer font, int ttcIndex);
     private static native boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
-            int ttcIndex, List<FontListParser.Axis> listOfAxis,
+            int ttcIndex, List<FontConfig.Axis> listOfAxis,
             int weight, boolean isItalic);
     private static native boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr,
             String path);
index 9490436..4ec564a 100644 (file)
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.text.FontConfig;
 import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -36,61 +37,8 @@ import java.util.regex.Pattern;
  */
 public class FontListParser {
 
-    public static class Config {
-        Config() {
-            families = new ArrayList<Family>();
-            aliases = new ArrayList<Alias>();
-        }
-        public List<Family> families;
-        public List<Alias> aliases;
-    }
-
-    public static class Axis {
-        Axis(int tag, float styleValue) {
-            this.tag = tag;
-            this.styleValue = styleValue;
-        }
-        public final int tag;
-        public final float styleValue;
-    }
-
-    public static class Font {
-        Font(String fontName, int ttcIndex, List<Axis> axes, int weight, boolean isItalic) {
-            this.fontName = fontName;
-            this.ttcIndex = ttcIndex;
-            this.axes = axes;
-            this.weight = weight;
-            this.isItalic = isItalic;
-        }
-        public String fontName;
-        public int ttcIndex;
-        public final List<Axis> axes;
-        public int weight;
-        public boolean isItalic;
-    }
-
-    public static class Alias {
-        public String name;
-        public String toName;
-        public int weight;
-    }
-
-    public static class Family {
-        public Family(String name, List<Font> fonts, String lang, String variant) {
-            this.name = name;
-            this.fonts = fonts;
-            this.lang = lang;
-            this.variant = variant;
-        }
-
-        public String name;
-        public List<Font> fonts;
-        public String lang;
-        public String variant;
-    }
-
     /* Parse fallback list (no names) */
-    public static Config parse(InputStream in) throws XmlPullParserException, IOException {
+    public static FontConfig parse(InputStream in) throws XmlPullParserException, IOException {
         try {
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(in, null);
@@ -104,9 +52,9 @@ public class FontListParser {
     // Note that a well-formed variation contains a four-character tag and a float as styleValue,
     // with spacers in between. The tag is enclosd either by double quotes or single quotes.
     @VisibleForTesting
-    public static Axis[] parseFontVariationSettings(String settings) {
+    public static FontConfig.Axis[] parseFontVariationSettings(String settings) {
         String[] settingList = settings.split(",");
-        ArrayList<Axis> axisList = new ArrayList<>();
+        ArrayList<FontConfig.Axis> axisList = new ArrayList<>();
         settingLoop:
         for (String setting : settingList) {
             int pos = 0;
@@ -148,9 +96,9 @@ public class FontListParser {
             }
             int tag = makeTag(tagString.charAt(0), tagString.charAt(1), tagString.charAt(2),
                     tagString.charAt(3));
-            axisList.add(new Axis(tag, styleValue));
+            axisList.add(new FontConfig.Axis(tag, styleValue));
         }
-        return axisList.toArray(new Axis[axisList.size()]);
+        return axisList.toArray(new FontConfig.Axis[axisList.size()]);
     }
 
     @VisibleForTesting
@@ -162,17 +110,17 @@ public class FontListParser {
         return c == ' ' || c == '\r' || c == '\t' || c == '\n';
     }
 
-    private static Config readFamilies(XmlPullParser parser)
+    private static FontConfig readFamilies(XmlPullParser parser)
             throws XmlPullParserException, IOException {
-        Config config = new Config();
+        FontConfig config = new FontConfig();
         parser.require(XmlPullParser.START_TAG, null, "familyset");
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             String tag = parser.getName();
             if (tag.equals("family")) {
-                config.families.add(readFamily(parser));
+                config.getFamilies().add(readFamily(parser));
             } else if (tag.equals("alias")) {
-                config.aliases.add(readAlias(parser));
+                config.getAliases().add(readAlias(parser));
             } else {
                 skip(parser);
             }
@@ -180,12 +128,12 @@ public class FontListParser {
         return config;
     }
 
-    private static Family readFamily(XmlPullParser parser)
+    private static FontConfig.Family readFamily(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         String name = parser.getAttributeValue(null, "name");
         String lang = parser.getAttributeValue(null, "lang");
         String variant = parser.getAttributeValue(null, "variant");
-        List<Font> fonts = new ArrayList<Font>();
+        List<FontConfig.Font> fonts = new ArrayList<FontConfig.Font>();
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             String tag = parser.getName();
@@ -195,18 +143,18 @@ public class FontListParser {
                 skip(parser);
             }
         }
-        return new Family(name, fonts, lang, variant);
+        return new FontConfig.Family(name, fonts, lang, variant);
     }
 
     /** Matches leading and trailing XML whitespace. */
     private static final Pattern FILENAME_WHITESPACE_PATTERN =
             Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
 
-    private static Font readFont(XmlPullParser parser)
+    private static FontConfig.Font readFont(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         String indexStr = parser.getAttributeValue(null, "index");
         int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
-        List<Axis> axes = new ArrayList<Axis>();
+        List<FontConfig.Axis> axes = new ArrayList<FontConfig.Axis>();
         String weightStr = parser.getAttributeValue(null, "weight");
         int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
         boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
@@ -225,7 +173,7 @@ public class FontListParser {
         }
         String fullFilename = "/system/fonts/" +
                 FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
-        return new Font(fullFilename, index, axes, weight, isItalic);
+        return new FontConfig.Font(fullFilename, index, axes, weight, isItalic);
     }
 
     /** The 'tag' attribute value is read as four character values between U+0020 and U+007E
@@ -239,7 +187,7 @@ public class FontListParser {
     private static final Pattern STYLE_VALUE_PATTERN =
             Pattern.compile("-?(([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))");
 
-    private static Axis readAxis(XmlPullParser parser)
+    private static FontConfig.Axis readAxis(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         int tag = 0;
         String tagStr = parser.getAttributeValue(null, "tag");
@@ -258,22 +206,22 @@ public class FontListParser {
         }
 
         skip(parser);  // axis tag is empty, ignore any contents and consume end tag
-        return new Axis(tag, styleValue);
+        return new FontConfig.Axis(tag, styleValue);
     }
 
-    private static Alias readAlias(XmlPullParser parser)
+    private static FontConfig.Alias readAlias(XmlPullParser parser)
             throws XmlPullParserException, IOException {
-        Alias alias = new Alias();
-        alias.name = parser.getAttributeValue(null, "name");
-        alias.toName = parser.getAttributeValue(null, "to");
+        String name = parser.getAttributeValue(null, "name");
+        String toName = parser.getAttributeValue(null, "to");
         String weightStr = parser.getAttributeValue(null, "weight");
+        int weight;
         if (weightStr == null) {
-            alias.weight = 400;
+            weight = 400;
         } else {
-            alias.weight = Integer.parseInt(weightStr);
+            weight = Integer.parseInt(weightStr);
         }
         skip(parser);  // alias tag is empty, ignore any contents and consume end tag
-        return alias;
+        return new FontConfig.Alias(name, toName, weight);
     }
 
     private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
index 2886f0d..764ab1c 100644 (file)
@@ -17,6 +17,7 @@
 package android.graphics;
 
 import android.content.res.AssetManager;
+import android.text.FontConfig;
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.LruCache;
@@ -294,25 +295,25 @@ public class Typeface {
         mStyle = nativeGetStyle(ni);
     }
 
-    private static FontFamily makeFamilyFromParsed(FontListParser.Family family,
+    private static FontFamily makeFamilyFromParsed(FontConfig.Family family,
             Map<String, ByteBuffer> bufferForPath) {
-        FontFamily fontFamily = new FontFamily(family.lang, family.variant);
-        for (FontListParser.Font font : family.fonts) {
-            ByteBuffer fontBuffer = bufferForPath.get(font.fontName);
+        FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
+        for (FontConfig.Font font : family.getFonts()) {
+            ByteBuffer fontBuffer = bufferForPath.get(font.getFontName());
             if (fontBuffer == null) {
-                try (FileInputStream file = new FileInputStream(font.fontName)) {
+                try (FileInputStream file = new FileInputStream(font.getFontName())) {
                     FileChannel fileChannel = file.getChannel();
                     long fontSize = fileChannel.size();
                     fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
-                    bufferForPath.put(font.fontName, fontBuffer);
+                    bufferForPath.put(font.getFontName(), fontBuffer);
                 } catch (IOException e) {
-                    Log.e(TAG, "Error mapping font file " + font.fontName);
+                    Log.e(TAG, "Error mapping font file " + font.getFontName());
                     continue;
                 }
             }
-            if (!fontFamily.addFontWeightStyle(fontBuffer, font.ttcIndex, font.axes,
-                    font.weight, font.isItalic)) {
-                Log.e(TAG, "Error creating font " + font.fontName + "#" + font.ttcIndex);
+            if (!fontFamily.addFontWeightStyle(fontBuffer, font.getTtcIndex(), font.getAxes(),
+                    font.getWeight(), font.isItalic())) {
+                Log.e(TAG, "Error creating font " + font.getFontName() + "#" + font.getTtcIndex());
             }
         }
         return fontFamily;
@@ -329,16 +330,16 @@ public class Typeface {
         File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG);
         try {
             FileInputStream fontsIn = new FileInputStream(configFilename);
-            FontListParser.Config fontConfig = FontListParser.parse(fontsIn);
+            FontConfig fontConfig = FontListParser.parse(fontsIn);
 
             Map<String, ByteBuffer> bufferForPath = new HashMap<String, ByteBuffer>();
 
             List<FontFamily> familyList = new ArrayList<FontFamily>();
             // Note that the default typeface is always present in the fallback list;
             // this is an enhancement from pre-Minikin behavior.
-            for (int i = 0; i < fontConfig.families.size(); i++) {
-                FontListParser.Family f = fontConfig.families.get(i);
-                if (i == 0 || f.name == null) {
+            for (int i = 0; i < fontConfig.getFamilies().size(); i++) {
+                FontConfig.Family f = fontConfig.getFamilies().get(i);
+                if (i == 0 || f.getName() == null) {
                     familyList.add(makeFamilyFromParsed(f, bufferForPath));
                 }
             }
@@ -346,10 +347,10 @@ public class Typeface {
             setDefault(Typeface.createFromFamilies(sFallbackFonts));
 
             Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
-            for (int i = 0; i < fontConfig.families.size(); i++) {
+            for (int i = 0; i < fontConfig.getFamilies().size(); i++) {
                 Typeface typeface;
-                FontListParser.Family f = fontConfig.families.get(i);
-                if (f.name != null) {
+                FontConfig.Family f = fontConfig.getFamilies().get(i);
+                if (f.getName() != null) {
                     if (i == 0) {
                         // The first entry is the default typeface; no sense in
                         // duplicating the corresponding FontFamily.
@@ -359,17 +360,17 @@ public class Typeface {
                         FontFamily[] families = { fontFamily };
                         typeface = Typeface.createFromFamiliesWithDefault(families);
                     }
-                    systemFonts.put(f.name, typeface);
+                    systemFonts.put(f.getName(), typeface);
                 }
             }
-            for (FontListParser.Alias alias : fontConfig.aliases) {
-                Typeface base = systemFonts.get(alias.toName);
+            for (FontConfig.Alias alias : fontConfig.getAliases()) {
+                Typeface base = systemFonts.get(alias.getToName());
                 Typeface newFace = base;
-                int weight = alias.weight;
+                int weight = alias.getWeight();
                 if (weight != 400) {
                     newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
                 }
-                systemFonts.put(alias.name, newFace);
+                systemFonts.put(alias.getName(), newFace);
             }
             sSystemFontMap = systemFonts;
 
index d046c11..2b4e6c2 100644 (file)
 package android.graphics;
 
 import android.test.suitebuilder.annotation.SmallTest;
+import android.text.FontConfig;
 import junit.framework.TestCase;
 
+import java.util.List;
+
 
 public class VariationParserTest extends TestCase {
 
     @SmallTest
     public void testParseFontVariationSetting() {
         int tag = FontListParser.makeTag('w', 'd', 't', 'h');
-        FontListParser.Axis[] axis = FontListParser.parseFontVariationSettings("'wdth' 1");
-        assertEquals(tag, axis[0].tag);
-        assertEquals(1.0f, axis[0].styleValue);
+        FontConfig.Axis[] axis = FontListParser.parseFontVariationSettings("'wdth' 1");
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(1.0f, axis[0].getStyleValue());
 
         axis = FontListParser.parseFontVariationSettings("\"wdth\" 100");
-        assertEquals(tag, axis[0].tag);
-        assertEquals(100.0f, axis[0].styleValue);
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(100.0f, axis[0].getStyleValue());
 
         axis = FontListParser.parseFontVariationSettings("   'wdth' 100");
-        assertEquals(tag, axis[0].tag);
-        assertEquals(100.0f, axis[0].styleValue);
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(100.0f, axis[0].getStyleValue());
 
         axis = FontListParser.parseFontVariationSettings("\t'wdth' 0.5");
-        assertEquals(tag, axis[0].tag);
-        assertEquals(0.5f, axis[0].styleValue);
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(0.5f, axis[0].getStyleValue());
 
         tag = FontListParser.makeTag('A', 'X', ' ', ' ');
         axis = FontListParser.parseFontVariationSettings("'AX  ' 1");
-        assertEquals(tag, axis[0].tag);
-        assertEquals(1.0f, axis[0].styleValue);
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(1.0f, axis[0].getStyleValue());
 
         axis = FontListParser.parseFontVariationSettings("'AX  '\t1");
-        assertEquals(tag, axis[0].tag);
-        assertEquals(1.0f, axis[0].styleValue);
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(1.0f, axis[0].getStyleValue());
 
         axis = FontListParser.parseFontVariationSettings("'AX  '\n1");
-        assertEquals(tag, axis[0].tag);
-        assertEquals(1.0f, axis[0].styleValue);
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(1.0f, axis[0].getStyleValue());
 
         axis = FontListParser.parseFontVariationSettings("'AX  '\r1");
-        assertEquals(tag, axis[0].tag);
-        assertEquals(1.0f, axis[0].styleValue);
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(1.0f, axis[0].getStyleValue());
 
         axis = FontListParser.parseFontVariationSettings("'AX  '\r\t\n 1");
-        assertEquals(tag, axis[0].tag);
-        assertEquals(1.0f, axis[0].styleValue);
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(1.0f, axis[0].getStyleValue());
 
         // Test for invalid input
         axis = FontListParser.parseFontVariationSettings("");
@@ -87,26 +90,26 @@ public class VariationParserTest extends TestCase {
 
     @SmallTest
     public void testParseFontVariationStyleSettings() {
-        FontListParser.Axis[] axis =
+        FontConfig.Axis[] axis =
                 FontListParser.parseFontVariationSettings("'wdth' 10,'AX  '\r1");
         int tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
         int tag2 = FontListParser.makeTag('A', 'X', ' ', ' ');
-        assertEquals(tag1, axis[0].tag);
-        assertEquals(10.0f, axis[0].styleValue);
-        assertEquals(tag2, axis[1].tag);
-        assertEquals(1.0f, axis[1].styleValue);
+        assertEquals(tag1, axis[0].getTag());
+        assertEquals(10.0f, axis[0].getStyleValue());
+        assertEquals(tag2, axis[1].getTag());
+        assertEquals(1.0f, axis[1].getStyleValue());
 
         // Test only spacers are allowed before tag
         axis = FontListParser.parseFontVariationSettings("     'wdth' 10,ab'wdth' 1");
         tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
-        assertEquals(tag1, axis[0].tag);
-        assertEquals(10.0f, axis[0].styleValue);
+        assertEquals(tag1, axis[0].getTag());
+        assertEquals(10.0f, axis[0].getStyleValue());
         assertEquals(1, axis.length);
     }
 
     @SmallTest
     public void testInvalidTagCharacters() {
-        FontListParser.Axis[] axis =
+        FontConfig.Axis[] axis =
                 FontListParser.parseFontVariationSettings("'\u0000\u0000\u0000\u0000' 10");
         assertEquals(0, axis.length);
         axis = FontListParser.parseFontVariationSettings("'\u3042\u3044\u3046\u3048' 10");
index 86cbb69..c9b3c6f 100644 (file)
@@ -823,11 +823,6 @@ android.graphics.DrawFilter
 android.graphics.EmbossMaskFilter
 android.graphics.FontFamily
 android.graphics.FontListParser
-android.graphics.FontListParser$Alias
-android.graphics.FontListParser$Axis
-android.graphics.FontListParser$Config
-android.graphics.FontListParser$Family
-android.graphics.FontListParser$Font
 android.graphics.Insets
 android.graphics.Interpolator
 android.graphics.Interpolator$Result
@@ -1847,6 +1842,11 @@ android.text.DynamicLayout
 android.text.DynamicLayout$ChangeWatcher
 android.text.Editable
 android.text.Editable$Factory
+android.text.FontConfig
+android.text.FontConfig$Alias
+android.text.FontConfig$Axis
+android.text.FontConfig$Family
+android.text.FontConfig$Font
 android.text.GetChars
 android.text.GraphicsOperations
 android.text.Html
diff --git a/services/core/java/com/android/server/FontManagerService.java b/services/core/java/com/android/server/FontManagerService.java
new file mode 100644 (file)
index 0000000..593c322
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.android.server;
+
+import android.content.Context;
+import android.graphics.FontListParser;
+import android.os.ParcelFileDescriptor;
+import android.text.FontConfig;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.font.IFontManager;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+public class FontManagerService extends IFontManager.Stub {
+    private static final String TAG = "FontManagerService";
+    private static final String FONTS_CONFIG = "/system/etc/fonts.xml";
+
+    @GuardedBy("mLock")
+    private FontConfig mConfig;
+    private final Object mLock = new Object();
+
+    public static final class Lifecycle extends SystemService {
+        private final FontManagerService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+            mService = new FontManagerService();
+        }
+
+        @Override
+        public void onStart() {
+            try {
+                publishBinderService(Context.FONT_SERVICE, mService);
+            } catch (Throwable t) {
+                // Starting this service is not critical to the running of this device and should
+                // therefore not crash the device. If it fails, log the error and continue.
+                Slog.e(TAG, "Could not start the FontManagerService.", t);
+            }
+        }
+    }
+
+    @Override
+    public FontConfig getSystemFonts() {
+        synchronized (mLock) {
+            if (mConfig != null) {
+                return new FontConfig(mConfig);
+            }
+
+            FontConfig config = loadFromSystem();
+            if (config == null) {
+                return null;
+            }
+
+            final int size = config.getFamilies().size();
+            for (int i = 0; i < size; ++i) {
+                FontConfig.Family family = config.getFamilies().get(i);
+                for (int j = 0; j < family.getFonts().size(); ++j) {
+                    FontConfig.Font font = family.getFonts().get(j);
+                    File fontFile = new File(font.getFontName());
+                    try {
+                        font.setFd(ParcelFileDescriptor.open(
+                                fontFile, ParcelFileDescriptor.MODE_READ_ONLY));
+                    } catch (IOException e) {
+                        Slog.e(TAG, "Error opening font file " + font.getFontName(), e);
+                    }
+                }
+            }
+
+            mConfig = config;
+            return new FontConfig(mConfig);
+        }
+    }
+
+    private FontConfig loadFromSystem() {
+        File configFilename = new File(FONTS_CONFIG);
+        try {
+            FileInputStream fontsIn = new FileInputStream(configFilename);
+            return FontListParser.parse(fontsIn);
+        } catch (IOException | XmlPullParserException e) {
+            Slog.e(TAG, "Error opening " + configFilename, e);
+        }
+        return null;
+    }
+
+    public FontManagerService() {
+    }
+}
index bedc6e1..951da37 100644 (file)
@@ -936,6 +936,12 @@ public final class SystemServer {
                 traceEnd();
             }
 
+            if (!disableNonCoreServices) {
+                traceBeginAndSlog("StartFontServiceManager");
+                mSystemServiceManager.startService(FontManagerService.Lifecycle.class);
+                traceEnd();
+            }
+
             if (!disableNonCoreServices && !disableTextServices) {
                 traceBeginAndSlog("StartTextServicesManager");
                 mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
index 50efc7f..d0c9599 100644 (file)
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.text.FontConfig;
 import com.android.ide.common.rendering.api.AssetRepository;
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.layoutlib.bridge.Bridge;
@@ -284,7 +285,7 @@ public class FontFamily_Delegate {
 
     @LayoutlibDelegate
     /*package*/ static boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
-            int ttcIndex, List<FontListParser.Axis> listOfAxis,
+            int ttcIndex, List<FontConfig.Axis> listOfAxis,
             int weight, boolean isItalic) {
         assert false : "The only client of this method has been overriden.";
         return false;
index 5cd34f6..6e337d5 100644 (file)
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.text.FontConfig;
 import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
@@ -208,12 +209,12 @@ public final class Typeface_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static FontFamily makeFamilyFromParsed(FontListParser.Family family,
+    /*package*/ static FontFamily makeFamilyFromParsed(FontConfig.Family family,
             Map<String, ByteBuffer> bufferForPath) {
-        FontFamily fontFamily = new FontFamily(family.lang, family.variant);
-        for (FontListParser.Font font : family.fonts) {
-            FontFamily_Delegate.addFont(fontFamily.mNativePtr, font.fontName, font.weight,
-                    font.isItalic);
+        FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
+        for (FontConfig.Font font : family.getFonts()) {
+            FontFamily_Delegate.addFont(fontFamily.mNativePtr, font.getFontName(),
+                    font.getWeight(), font.isItalic());
         }
         return fontFamily;
     }