androidandroid-studiofontsfont-facefont-style

Making an app that changes device fonts for galaxy phones


I want to make an app that can change system font style in galaxy phone after installing my app user can change font from Setting>my Device >font style and choose from list without requiring root permission. I have my own font style in true type file.

enter image description here

enter image description here

enter image description here

manidest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="2" android:versionName="1.1" package="com.monotype.android.font.presentltroman" platformBuildVersionCode="23" platformBuildVersionName="6.0-2438415">
    <uses-sdk android:minSdkVersion="7" />
    <application android:label="@string/app_name" android:icon="@drawable/icon">
        <provider android:name=".FontContentProvider" android:authorities="com.example.myfont" />
        <support-screens android:largeScreens="true" android:xlargeScreens="true" />
    </application>
</manifest>

There is only one activity

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.FileNotFoundException;

public class FontContentProvider extends ContentProvider {
    private static final UriMatcher uriMatcher = new UriMatcher(-1);

    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
        return null;
    }

    public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
        String file_name = uri.getPath();
        if (file_name == null) {
            throw new FileNotFoundException();
        }
        if (file_name.startsWith("/")) {
            file_name = file_name.substring(1);
        }
        AssetFileDescriptor ad = null;
        try {
            ad = getContext().getAssets().openFd(file_name);
        } catch (Exception e) {
            Log.v("CPFontTest", "cp - openAssetFile EXCEPTION");
        }
        return ad;
    }

    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }

    public String getType(Uri uri) {
        AssetManager am = getContext().getAssets();
        StringBuilder xmlfileStringBuilder = new StringBuilder();
        try {
            for (String s : am.list("xml")) {
                xmlfileStringBuilder.append(s + "\n");
            }
            return xmlfileStringBuilder.toString();
        } catch (Exception e) {
            return null;
        }
    }

    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    public boolean onCreate() {
        return true;
    }

    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        return null;
    }

    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        return 0;
    }

    static {
        uriMatcher.addURI(".fontcontentprovider", "fonts", 1);
    }
}

Solution

  • TL;DR: To create a FlipFont you need a valid font file and XML file in assets. The APK needs to be signed with Monotype's private keystore, which isn't possible.


    Samsung and other manufacturers use Monotype's FlipFont to change the system fonts without root. Samsung and Monotype Imaging Inc. want you to pay to change fonts and have made concerted efforts to block free fonts from being installed.

    You don't need any code to create a font for FlipFont, so you can delete FontContentProvider.java.

    To create an APK that works with FlipFont you need the following 3 things:

    1) A valid font file in assets/fonts/ReplaceWithFontName.ttf

    2) An XML in assets/xml/ReplaceWithFontName.xml

    3) Build and sign the app with Monotype's private keystore.

    Example XML for assets:

    <?xml version="1.0" encoding="utf-8"?>
    <font displayname="ReplaceWithFontName">
      <sans>
        <file>
          <filename>ReplaceWithFontName.ttf</filename>
          <droidname>DroidSans.ttf</droidname>
        </file>
        <file>
          <filename>ReplaceWithFontName.ttf</filename>
          <droidname>DroidSans-Bold.ttf</droidname>
        </file>
      </sans>
    </font>
    

    Now, look at #3 again. You need to sign the APK with Monotype's keystore. You don't have access to this. Therefore, your APK will not work on Samsung devices.

    The following method is decompiled from the Settings application on a Samsung device and is used to check if the FlipFont APK is signed with the correct key:

    protected boolean checkFont(String apkname) {
      if (DEBUG) {
        Log.secD("FlipFont", "checkFont - checking apkname" + apkname);
      }
      if ("com.monotype.android.font.foundation".equals(apkname)) {
        return false;
      }
      PackageManager pm = this.mContext.getPackageManager();
      for (int i = 0; i < apkNameList.length; i++) {
        if (apkname != null) {
          if (apkname.equals(apkNameList[i])) {
            this.isCheckPlatformSignatures = pm.checkSignatures("android", apkNameList[i]) == 0;
            this.isCheckReleaseSignatures = Utils.isSignatureMatch(this.mContext, apkNameList[i]);
            Log.i("FontPreviewTablet", "apkname : " + apkname + ", isCheckPlatformSignatures : " + this.isCheckPlatformSignatures + ", isCheckReleaseSignatures : " + this.isCheckReleaseSignatures);
            if (!(this.isCheckPlatformSignatures || this.isCheckReleaseSignatures)) {
              if (apkname.equals("")) {
              }
            }
            return false;
          }
          continue;
        }
      }
      if (DEBUG) {
        Log.secD("FlipFont", "checkFont - check if valid certificate");
      }
      PackageInfo packageInfo = null;
      try {
        packageInfo = this.mFontListAdapter.mPackageManager.getPackageInfo(apkname, 64);
      } catch (Exception e) {
      }
      if (packageInfo != null) {
        Signature[] signatures = packageInfo.signatures;
        byte[] cert = signatures[0].toByteArray();
        try {
          MessageDigest md = MessageDigest.getInstance("SHA");
          md.update(signatures[0].toByteArray());
          if ("T84drf8v3ZMOLvt2SFG/K7ODXgI=".equals(Base64.encodeToString(md.digest(), 0).trim())) {
            if (DEBUG) {
              Log.v("FlipFont", "**Signature is correct**");
            }
            return false;
          }
          if (DEBUG) {
            Log.v("FlipFont", "**Signature is incorrect**");
          }
          return true;
        } catch (Exception e2) {
          e2.printStackTrace();
          InputStream input = new ByteArrayInputStream(cert);
          CertificateFactory cf = null;
          try {
            cf = CertificateFactory.getInstance("X509");
          } catch (CertificateException e3) {
            e3.printStackTrace();
          }
          X509Certificate c = null;
          try {
            c = (X509Certificate) cf.generateCertificate(input);
          } catch (CertificateException e32) {
            e32.printStackTrace();
          }
          if (DEBUG) {
            Log.secD("Example", "APK name: " + apkname);
            if (c != null) {
              Log.secD("Example", "Certificate for: " + c.getSubjectDN());
              Log.secD("Example", "Certificate issued by: " + c.getIssuerDN());
              Log.secD("Example", "The certificate is valid from " + c.getNotBefore() + " to " + c.getNotAfter());
              Log.secD("Example", "Certificate SN# " + c.getSerialNumber());
              Log.secD("Example", "Generated with " + c.getSigAlgName());
            }
          }
          String certIssuedByString = "CN=Ed Platz, OU=Display Imaging, O=Monotype Imanging Inc., L=Woburn, ST=MA, C=US";
          if (c != null && certIssuedByString.equals(c.getIssuerDN().toString())) {
            if (DEBUG) {
              Log.secD("FlipFont", "**Certificate data is correct**");
            }
            return false;
          }
        }
      }
      return true;
    }
    

    If you look at the above method you will notice that the APK signature isn't checked if the APK has a package name of "com.monotype.android.font.foundation".