1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.intelligence.search.sitemap; 18 19 import android.content.Context; 20 import android.database.Cursor; 21 import android.database.sqlite.SQLiteDatabase; 22 import androidx.annotation.WorkerThread; 23 import android.text.TextUtils; 24 import android.util.Log; 25 26 import com.android.settings.intelligence.search.indexing.IndexDatabaseHelper; 27 import com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.SiteMapColumns; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 32 public class SiteMapManager { 33 34 private static final String TAG = "SiteMapManager"; 35 private static final boolean DEBUG_TIMING = false; 36 37 public static final String[] SITE_MAP_COLUMNS = { 38 SiteMapColumns.PARENT_CLASS, 39 SiteMapColumns.PARENT_TITLE, 40 SiteMapColumns.CHILD_CLASS, 41 SiteMapColumns.CHILD_TITLE 42 }; 43 44 private final List<SiteMapPair> mPairs = new ArrayList<>(); 45 46 private boolean mInitialized; 47 48 /** 49 * Given a fragment class name and its screen title, build a breadcrumb from Settings root to 50 * this screen. 51 * <p/> 52 * Not all screens have a full breadcrumb path leading up to root, it's because either some 53 * page in the breadcrumb path is not indexed, or it's only reachable via search. 54 */ 55 @WorkerThread buildBreadCrumb(Context context, String clazz, String screenTitle)56 public synchronized List<String> buildBreadCrumb(Context context, String clazz, 57 String screenTitle) { 58 init(context); 59 final long startTime = System.currentTimeMillis(); 60 final List<String> breadcrumbs = new ArrayList<>(); 61 if (!mInitialized) { 62 Log.w(TAG, "SiteMap is not initialized yet, skipping"); 63 return breadcrumbs; 64 } 65 if (!TextUtils.isEmpty(screenTitle)) { 66 breadcrumbs.add(screenTitle); 67 } 68 String currentClass = clazz; 69 String currentTitle = screenTitle; 70 // Look up current page's parent, if found add it to breadcrumb string list, and repeat. 71 while (true) { 72 final SiteMapPair pair = lookUpParent(currentClass, currentTitle); 73 if (pair == null) { 74 if (DEBUG_TIMING) { 75 Log.d(TAG, "BreadCrumb timing: " + (System.currentTimeMillis() - startTime)); 76 } 77 return breadcrumbs; 78 } 79 final String parentTitle = pair.getParentTitle(); 80 if (!TextUtils.isEmpty(parentTitle)) { 81 breadcrumbs.add(0, parentTitle); 82 } 83 currentClass = pair.getParentClass(); 84 currentTitle = pair.getParentTitle(); 85 } 86 } 87 88 /** 89 * Initialize a list of {@link SiteMapPair}s. Each pair knows about a single parent-child 90 * page relationship. 91 */ 92 @WorkerThread init(Context context)93 private synchronized void init(Context context) { 94 if (mInitialized) { 95 // Make sure only init once. 96 return; 97 } 98 final long startTime = System.currentTimeMillis(); 99 // First load site map from static index table. 100 final Context appContext = context.getApplicationContext(); 101 final SQLiteDatabase db = IndexDatabaseHelper.getInstance(appContext).getReadableDatabase(); 102 Cursor sitemap = db.query(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, SITE_MAP_COLUMNS, null, 103 null, null, null, null); 104 while (sitemap.moveToNext()) { 105 final SiteMapPair pair = new SiteMapPair( 106 sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.PARENT_CLASS)), 107 sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.PARENT_TITLE)), 108 sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.CHILD_CLASS)), 109 sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.CHILD_TITLE))); 110 mPairs.add(pair); 111 } 112 sitemap.close(); 113 // Done. 114 mInitialized = true; 115 if (DEBUG_TIMING) { 116 Log.d(TAG, "Init timing: " + (System.currentTimeMillis() - startTime)); 117 } 118 } 119 120 @WorkerThread lookUpParent(String clazz, String title)121 private SiteMapPair lookUpParent(String clazz, String title) { 122 for (SiteMapPair pair : mPairs) { 123 if (TextUtils.equals(pair.getChildClass(), clazz) 124 && TextUtils.equals(title, pair.getChildTitle())) { 125 return pair; 126 } 127 } 128 return null; 129 } 130 131 } 132