1

I want to download and save a .ttf or .otf file for custom fonts in my Android App. Is it possible to save this in SharedPreferences?

Not the file path, but the file itself.

Edit: I asked for this method because OutputStream kept giving me 'Permission Denied' error. I am open to any suggestion that would help me save the downloaded .ttf to files and retrieve it later.

Thanks!

Edit: I have added the Input Output Stream code below, which gives me a permission denied error when running. Please let me know if I can fix something here.

class DownloadFileFromURL extends AsyncTask<String, String, String> {
@Override
protected String doInBackground(String... f_url) {
    int count;
    try {
        URL url = new URL(f_url[0]);
        URLConnection connection = url.openConnection();
        connection.connect();
        // this will be useful so that you can show a typical 0-100% progress bar
        int lenghtOfFile = connection.getContentLength();

        InputStream input = new BufferedInputStream(url.openStream(), 8192);
        File file = new File(Environment.getExternalStorageDirectory(), "downloadedFont.ttf");
        OutputStream output = new FileOutputStream(file);

        byte data[] = new byte[1024];
            long total = 0;
            while ((count = input.read(data)) != -1) {
                total += count;
                publishProgress(""+(int)((total*100)/lenghtOfFile));
                output.write(data, 0, count);
            }
            output.flush();
            output.close();
            input.close();

    } catch (Exception e) {
        Log.e("Error", e.getMessage() + e.getCause());
    }
    return null;
}

@Override
protected void onPostExecute(String file_url) {
    loadFont();
}

public static void loadFont() {
    File file = new File(Environment.getExternalStorageDirectory().toString() + "/downloadedFont.ttf");
    if(file.exists()){
        Log.d("LOAD", "File exists");
        Typeface typeFace = Typeface.createFromFile(file);
        ContextHelper.setDownloadedFontType(typeFace);
    }
    else {
        download();
    }
}

public static void download() {
    Log.d("DOWNLOAD", "In the download.");
    new DownloadFileFromURL().execute("https://www.dropbox.com/s/y980vywiprd8eci/riesling.ttf?raw=1");
}
}

The following is how the method is called in an Activity.

DownloadFileFromURL.loadFont();
PWJ
  • 83
  • 10
  • 3
    Why would you place a file in another file? Just copy the file to getFilesDir(). Thats the place where the shared preferences files are saved too. – blackapps Apr 08 '21 at 07:13
  • SharedPreferences is a XML that needs to be read in whole and written in whole. Every time you add a font, the whole file needs to be re-written to disk. Fonts can easily reach hundreds of kilobytes each. Plus [SharedPreferences kinda sucks](https://android-developers.googleblog.com/2020/09/prefer-storing-data-with-jetpack.html). – Eugen Pechanec Apr 08 '21 at 07:15
  • You probably want to save the actual font in a separate file and store the name of the font in SharedPreferences, so you can load it later, right? – Eugen Pechanec Apr 08 '21 at 07:18
  • @blackapps Are you able to let me know how to do that? I have tried InputStream and OutputStream, but I keep getting Permission Denied, which is why I wanted to try another method. – PWJ Apr 08 '21 at 07:33
  • You can convert you file to bytes and save it in prefererences in theory. But as said before - it is very bad practice. Mb you getting Permision Denied because of missign permissions in Manifest? – Yegorf Apr 08 '21 at 07:50
  • @Yegorf I added the read and write permissions to the Manifest file. – PWJ Apr 08 '21 at 08:15
  • And? What is result?) Dont forget to ask user for this permisions. He should accept it. Or you can just set in app settings. – Yegorf Apr 08 '21 at 08:20
  • @Yegorf Even after adding to Manifest file, it still says Permission Denied. I also allowed storage permission in app settings. Even then, it is permission denied. – PWJ Apr 08 '21 at 08:31
  • `I have tried InputStream and OutputStream, ` That is very ok. There is nothing special what you have to do. Just a normal copy file function. Show your code if anything does not work. You do not need any permission for using OutputStream for files in getFilesDir(). So permission problems arise from the source file. Tell where it is located and tell which Android version(s) on used device(s).; – blackapps Apr 08 '21 at 09:39
  • @blackapps I have added the code to my initial question. Do you mean that it might be an issue where the dropbox link is concerned? Most answers I've looked through seem to say it is an output permission issue. Also, to use getFilesDir(), I would need to pass context and I don't know how I would do that since this is a different class altogether. – PWJ Apr 08 '21 at 10:06
  • `File file = new File(Environment.getExternalStorageDirectory(), "downloadedFont.ttf"); `. You should change that to `File file = new File(getFilesDir(), "downloadedFont.ttf");` And put that statement before you call your asynctask. or `DownloadFileFromURL.loadFont();` And change that to `DownloadFileFromURL.loadFont(file);` And use the extra parameter too for you asynctask. – blackapps Apr 08 '21 at 10:46

2 Answers2

1

I thought that's possible. Download File first convert to Base64 Encoding save that encoding data in Share Pref. When you Fetch it Decoding and create a file again and use it.

HiteshGs
  • 539
  • 2
  • 7
  • 18
1

After much searching, I found the answer in the depths of StackOverflow:

public static void downloadFont(String url, Context context) {
    DownloadManager.Request request1 = new DownloadManager.Request(Uri.parse(url));
    request1.setDescription("Sample Font File");
    request1.setTitle("Font.ttf");
    request1.setVisibleInDownloadsUi(false);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        request1.allowScanningByMediaScanner();
        request1.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
    }
    request1.setDestinationInExternalFilesDir(context, "/File", "Font.ttf");

    DownloadManager manager1 = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
    Objects.requireNonNull(manager1).enqueue(request1);

    if (DownloadManager.STATUS_SUCCESSFUL == 8) {
        File file = new File(context.getExternalFilesDir("/File").toString() + "/Font.ttf");
        if(file.exists()){
            Typeface typeFace = Typeface.createFromFile(file);
        }
    }
}

Many thanks to this answer which helped solve my problem so concisely.

PWJ
  • 83
  • 10